gpt4 book ai didi

c# - 当 xml 有缩进/换行符时,字典的自定义序列化失败

转载 作者:行者123 更新时间:2023-11-30 23:09:23 26 4
gpt4 key购买 nike

为了使字典序列化的 XML 更清晰,我编写了一个自定义类,它实现了 IXmlSerializable

我的自定义类是这样定义的:

public class MyCollection : System.Collections.Generic.Dictionary<string, string>, IXmlSerializable
{
private const string XmlElementName = "MyData";
private const string XmlAttributeId = "Id";

public XmlSchema GetSchema()
{
return null;
}

public void ReadXml(XmlReader reader)
{
reader.MoveToContent();
while (reader.Read())
{
if(reader.LocalName == XmlElementName)
{
var tag = reader.GetAttribute(XmlAttributeId);
var content = reader.ReadElementContentAsString();

this.Add(tag, content);
}
}
}

public void WriteXml(System.Xml.XmlWriter writer)
{
foreach (string key in this.Keys)
{
writer.WriteStartElement(XmlElementName);
writer.WriteAttributeString(XmlAttributeId, key);
writer.WriteString(this[key]);
writer.WriteEndElement();
}
}
}

我的代码使用这个 XML 片段:

<MyCollection xmlns="http://schemas.datacontract.org/2004/07/MyProject" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<MyData Id="1">some content</MyData>
<MyData Id="2">some other content</MyData>
</MyCollection>

但是,当我有这个缩小的 XML 时,我的代码会抛出一个异常:

<MyCollection xmlns="http://schemas.datacontract.org/2004/07/MyProject" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><MyData Id="1">some content </MyData><MyData Id="2">some other content</MyData></MyCollection>

异常(exception)情况是:

System.InvalidOperationException: The ReadElementContentAsString method is not supported on node type EndElement

它在调用 ReadElementContentAsString 时抛出。

如何修复我的代码?

我可以重现问题:

var xml = @"<MyCollection xmlns=""http://schemas.datacontract.org/2004/07/MyProject"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><MyData Id=""1"">some content </MyData><MyData Id=""2"">some other content</MyData></MyCollection>";

var raw = Encoding.UTF8.GetBytes(xml);

var serializer = new DataContractSerializer(typeof(MyCollection));

using (var ms = new MemoryStream(raw))
{
var result = serializer.ReadObject(ms); // Exception throws here
}

最佳答案

你的问题是reader.ReadElementContentAsString()将阅读器定位在下一个节点的开头,而不是当前节点的结尾。然后,您随后无条件调用 reader.Read()消耗下一个节点。当该节点是空白时,不会造成任何伤害,但当该节点是一个元素时,该元素将被跳过。

MyCollection 的以下版本修复了这个问题:

public class MyCollection : System.Collections.Generic.Dictionary<string, string>, IXmlSerializable
{
public XmlSchema GetSchema()
{
return null;
}

public void ReadXml(XmlReader reader)
{
using (var subReader = reader.ReadSubtree())
{
XmlKeyValueListHelper.ReadKeyValueXml(subReader, this);
}
// Consume the EndElement also (or move past the current element if reader.IsEmptyElement).
reader.Read();
}

public void WriteXml(System.Xml.XmlWriter writer)
{
XmlKeyValueListHelper.WriteKeyValueXml(writer, this);
}
}

public static class XmlKeyValueListHelper
{
private const string XmlElementName = "MyData";
private const string XmlAttributeId = "Id";

public static void WriteKeyValueXml(System.Xml.XmlWriter writer, ICollection<KeyValuePair<string, string>> collection)
{
foreach (var pair in collection)
{
writer.WriteStartElement(XmlElementName);
writer.WriteAttributeString(XmlAttributeId, pair.Key);
writer.WriteString(pair.Value);
writer.WriteEndElement();
}
}

public static void ReadKeyValueXml(System.Xml.XmlReader reader, ICollection<KeyValuePair<string, string>> collection)
{
if (reader.IsEmptyElement)
{
reader.Read();
return;
}

reader.ReadStartElement(); // Advance to the first sub element of the list element.
while (reader.NodeType != XmlNodeType.EndElement)
{
if (reader.NodeType == XmlNodeType.Element && reader.LocalName == XmlElementName)
{
var tag = reader.GetAttribute(XmlAttributeId);
string content;
if (reader.IsEmptyElement)
{
content = string.Empty;
// Move past the end of item element
reader.Read();
}
else
{
// Read content and move past the end of item element
content = reader.ReadElementContentAsString();
}
collection.Add(new KeyValuePair<string, string>(tag, content));
}
else
{
// For instance a comment.
reader.Skip();
}
}
// Move past the end of the list element
reader.ReadEndElement();
}
}

一些注意事项:

  • 通过使用 XmlReader.ReadSubtree()我确保 ReadXml() 不会读取超过 MyCollection 元素的末尾,从而破坏 future 的元素——这是实现 IXmlSerializable 时容易犯的错误>.

  • 通过检查 reader.NodeType == XmlNodeType.Element && reader.LocalName == XmlElementName,我忽略了意外类型的节点,例如注释。

工作 .Net fiddle .

关于c# - 当 xml 有缩进/换行符时,字典的自定义序列化失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45844241/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com