Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 当xml具有缩进/换行符时,字典的自定义序列化失败_C#_Xml_Serialization_Ixmlserializable - Fatal编程技术网

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

C# 当xml具有缩进/换行符时,字典的自定义序列化失败,c#,xml,serialization,ixmlserializable,C#,Xml,Serialization,Ixmlserializable,为了使字典序列化的XML更清晰,我编写了一个自定义类,它实现了IXmlSerializable 我的自定义类定义如下: public class MyCollection : System.Collections.Generic.Dictionary<string, string>, IXmlSerializable { private const string XmlElementName = "MyData"; private const string XmlAt

为了使字典序列化的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();
        }
    }
}
它在调用
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
}
var xml=@“一些内容一些其他内容”;
var raw=Encoding.UTF8.GetBytes(xml);
var serializer=新的DataContractSerializer(typeof(MyCollection));
使用(var ms=新内存流(原始))
{
var result=serializer.ReadObject(ms);//此处抛出异常
}
您的问题是将读卡器定位在下一个节点的开头,而不是当前节点的结尾。然后,对的后续无条件调用将使用下一个节点。当该节点为空白时,不会造成任何伤害,但当该节点为元素时,将跳过该元素

以下版本的
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();
    }
}
公共类MyCollection:System.Collections.Generic.Dictionary,IXmlSerializable { 公共XmlSchema GetSchema() { 返回null; } 公共void ReadXml(XmlReader) { 使用(var subReader=reader.ReadSubtree()) { ReadKeyValueXml(子读取器,this); } //同时使用EndElement(如果reader.IsEmptyElement,则移动当前元素)。 reader.Read(); } public void WriteXml(System.Xml.XmlWriter) { WriteKeyValueXml(writer,this); } } 公共静态类XmlKeyValueListHelper { 私有常量字符串xmlementname=“MyData”; 私有常量字符串XmlAttributeId=“Id”; 公共静态void WriteKeyValueXml(System.Xml.XmlWriter writer,ICollection集合) { foreach(集合中的变量对) { writer.writeStarteElement(XmlElementName); WriteAttributeString(XmlAttributeId,pair.Key); writer.WriteString(pair.Value); writer.writeedelement(); } } 公共静态void ReadKeyValueXml(System.Xml.XmlReader阅读器,ICollection集合) { if(读卡器ISemptyelment) { reader.Read(); 返回; } reader.ReadStartElement();//前进到list元素的第一个子元素。 while(reader.NodeType!=XmlNodeType.EndElement) { if(reader.NodeType==XmlNodeType.Element&&reader.LocalName==XmlElementName) { var tag=reader.GetAttribute(XmlAttributeId); 字符串内容; if(读卡器ISemptyelment) { content=string.Empty; //移动到项目结束元素之后 reader.Read(); } 其他的 { //读取内容并移过项目结束元素 content=reader.ReadElementContentAsString(); } 添加(新的KeyValuePair(标记、内容)); } 其他的 { //比如一条评论。 reader.Skip(); } } //移动到列表元素的末尾 reader.ReadEndElement(); } } 一些注意事项:

  • 通过使用,我可以确保
    ReadXml()
    的读取不会超过
    MyCollection
    元素的末尾,从而损坏未来的元素——在实现
    IXmlSerializable
    时很容易犯错误

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


正在工作。

如果将代码更改为:
if(reader.LocalName==xmlementname&&reader.NodeType==XmlNodeType.Element)
。当您在结束标签上时,您似乎正在尝试阅读元素内容。谢谢,它工作起来很有魅力。使用XmlReader并不明显:(
System.InvalidOperationException: The ReadElementContentAsString method is not supported on node type EndElement
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
}
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();
    }
}