C# 中的 IXmlSerialized 字典不带“Key”/“Value”节点
我正在尝试用 C# 序列化字典。所有 示例 我已经找到创建 XML如下所示:
<Dictionary>
<ArrayOfEntries>
<Entry>
<Key>myFirstKey</Key>
<Value>myFirstValue</Value>
</Entry>
<Entry>
<Key>mySecondKey</Key>
<Value>mySecondValue</Value>
</Entry>
</ArrayOfEntries>
</Dictionary>
它有所不同,有时 ArrayOfEntries 节点不是必需的,但我仍然看到字典的键值对存储在其自己的节点中的常规模式。我想要的是类似以下内容:
<Dictionary>
<myFirstKey>myFirstValue</myFirstKey>
<mySecondKey>mySecondValue</mySecondKey>
</Dictionary>
我之前已经编写了 ReadXml
和 WriteXml
来执行此操作,并且它适用于单个字典,但是如果我尝试序列化和反序列化我的可序列化字典实例的 List
,反序列化列表最终仅包含最后可序列化字典。我认为我的读取或写入方法一定是贪婪的,以至于它不知道何时停止。以下是我的可序列化字典方法,目前不适用于可序列化字典的 List
的序列化:
public void WriteXml(XmlWriter writer)
{
foreach (string key in getKeysToSerialize())
{
string cleanKey = key.SanitizeForXml();
string value = getValueForKey(key).Trim();
if (isCdata(key, value))
{
string cdataFriendlyValue = cleanStringForUseInCdata(value);
if (string.IsNullOrEmpty(cdataFriendlyValue))
{
continue;
}
writer.WriteStartElement(cleanKey);
writer.WriteCData(cdataFriendlyValue);
writer.WriteEndElement();
}
else
{
writer.WriteElementString(cleanKey, value);
}
}
}
和 ReadXml
:
public void ReadXml(XmlReader reader)
{
string key = null, value = null;
bool wasEmpty = reader.IsEmptyElement;
while (reader.Read())
{
if (wasEmpty)
{
return;
}
switch (reader.NodeType)
{
case XmlNodeType.Element:
key = reader.Name;
if (keyIsSubTree(key))
{
using (XmlReader subReader = reader.ReadSubtree())
{
storeSubtree(key, subReader);
}
// Reset key to null so we don't try to parse it as
// a regular key-value pair later
key = null;
}
break;
case XmlNodeType.Text:
value = reader.Value;
break;
case XmlNodeType.CDATA:
value = cleanCdataForStoring(reader.Value);
break;
case XmlNodeType.EndElement:
if (!string.IsNullOrEmpty(key))
{
string valueToStore =
string.IsNullOrEmpty(value) ? string.Empty : value
Add(key, valueToStore);
}
key = null;
value = null;
break;
}
}
}
我注意到其他教程之间的一个区别是什么我正在做的是,许多人使用 XmlSerializer
来序列化和反序列化其 ReadXml
和 WriteXml
中的对象,而我使用 WriteElementString
代码>等等。
我的问题是,如何序列化字典,使其 XML 类似于上面的第二个 XML 示例,但序列化和反序列化 List
也可以工作?即使只是暗示“你为什么要这么做,这可能会让事情变得很有趣”也会有所帮助。
I'm trying to serialize a dictionary in C#. All the examples I've been able to find create XML like the following:
<Dictionary>
<ArrayOfEntries>
<Entry>
<Key>myFirstKey</Key>
<Value>myFirstValue</Value>
</Entry>
<Entry>
<Key>mySecondKey</Key>
<Value>mySecondValue</Value>
</Entry>
</ArrayOfEntries>
</Dictionary>
It varies, sometimes the ArrayOfEntries
node isn't necessary, but I still see the regular pattern of the dictionary's key-value pairs being stored in their own nodes. What I would like is something like the following:
<Dictionary>
<myFirstKey>myFirstValue</myFirstKey>
<mySecondKey>mySecondValue</mySecondKey>
</Dictionary>
I have written ReadXml
and WriteXml
to do this before and it works for a single dictionary, but if I try to serialize and deserialize a List<T>
of my serializable dictionary instances, the deserialized list ends up with only the last serializable dictionary in it. I think something must be greedy about my read or write method such that it doesn't know when to stop. Here are my serializable dictionary methods that currently don't work for serialization of List
's of serializable dictionaries:
public void WriteXml(XmlWriter writer)
{
foreach (string key in getKeysToSerialize())
{
string cleanKey = key.SanitizeForXml();
string value = getValueForKey(key).Trim();
if (isCdata(key, value))
{
string cdataFriendlyValue = cleanStringForUseInCdata(value);
if (string.IsNullOrEmpty(cdataFriendlyValue))
{
continue;
}
writer.WriteStartElement(cleanKey);
writer.WriteCData(cdataFriendlyValue);
writer.WriteEndElement();
}
else
{
writer.WriteElementString(cleanKey, value);
}
}
}
And ReadXml
:
public void ReadXml(XmlReader reader)
{
string key = null, value = null;
bool wasEmpty = reader.IsEmptyElement;
while (reader.Read())
{
if (wasEmpty)
{
return;
}
switch (reader.NodeType)
{
case XmlNodeType.Element:
key = reader.Name;
if (keyIsSubTree(key))
{
using (XmlReader subReader = reader.ReadSubtree())
{
storeSubtree(key, subReader);
}
// Reset key to null so we don't try to parse it as
// a regular key-value pair later
key = null;
}
break;
case XmlNodeType.Text:
value = reader.Value;
break;
case XmlNodeType.CDATA:
value = cleanCdataForStoring(reader.Value);
break;
case XmlNodeType.EndElement:
if (!string.IsNullOrEmpty(key))
{
string valueToStore =
string.IsNullOrEmpty(value) ? string.Empty : value
Add(key, valueToStore);
}
key = null;
value = null;
break;
}
}
}
One difference I've noticed between other tutorials and what I'm doing is that many use XmlSerializer
to serialize and deserialize objects in their ReadXml
and WriteXml
, whereas I use WriteElementString
and the like.
My question is, how can I serialize a dictionary such that its XML is like my second XML example above, but so that serializing and deserializing a List<MySerializableDictionary>
also works? Even just hints of "why are you doing blah, that might make it act funny" would help.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我的
WriteXml
看起来没问题,因为它以我想要的 XML 格式输出字典的内容。ReadXml
是我出错的地方。基于本教程中的ReadXml
实现,我想出了以下结论:这似乎适用于只有一个键值对的字典以及具有多个键值对的字典。我对字典
List
进行序列化/反序列化的测试也有效。我还没有为 CDATA 添加任何特殊处理,我确信这是必要的。不过,这似乎是一个开始。编辑:实际上,也许我只需要在编写时担心CDATA,而不是在阅读时。
编辑:更新了上面的
ReadXml
代码,以考虑反序列化时在 XML 文件中找到的XmlNodeType.Whitespace
。我收到 XML 错误,因为在reader.NodeType
不是XmlNodeType.EndElement
时调用ReadEndElement
。对此进行检查,以便它仅在EndElement
时调用ReadEndElement
,并且还更改了外部while
循环,以便读者可以继续进行(通过Read()
),当它没有命中Element
并且没有命中EndElement
(例如,它命中了>空白
)。My
WriteXml
seemed okay because it outputs the dictionary's content in the XML format I want.ReadXml
was where I was going wrong. Based on theReadXml
implementation found in this tutorial, I came up with the following:This seemed to work for dictionaries that had only one key-value pair as well as dictionaries with multiple key-value pairs. My test of serializing/deserializing a
List<T>
of dictionaries also worked. I haven't added any special handling for CDATA yet, and I'm sure that will be necessary. This seems like a start, though.Edit: actually, maybe I only need to worry about CDATA when I'm writing, not when reading.
Edit: updated
ReadXml
code above to account forXmlNodeType.Whitespace
, which is found in XML files when you're deserializing. I was getting an XML error becauseReadEndElement
was being called when thereader.NodeType
was not anXmlNodeType.EndElement
. Put in a check for that so it only callsReadEndElement
when it's anEndElement
, and also changed the outerwhile
loop so the reader can progress (viaRead()
) when it hasn't hit anElement
and it hasn't hit anEndElement
(e.g., it has hitWhitespace
).