XmlSerializer 生成错误顺序的重复序列

Posted

技术标签:

【中文标题】XmlSerializer 生成错误顺序的重复序列【英文标题】:XmlSerializer generates wrong order of repeated sequence 【发布时间】:2019-09-20 18:58:09 【问题描述】:

当我在xsd:sequence 上有中继器时

例如:<xsd:sequence minOccurs="1" maxOccurs="unbounded">

这将是匹配的 xml:

<Element>
  <name>e1</name>
  <number>n1</number>
  <details>i1</details>
  <name>e2</name>
  <number>n2</number>
  <details>i2</details>
  <name>e3</name>
  <number>n3</number>
  <details>i3</details>
</Element>

另一方面,当我在元素上有一个中继器时:

<xsd:sequence>
    <xsd:element name="name" type="xsd:token" minOccurs="1" maxOccurs="unbounded"/>
    <xsd:element name="number" type="xsd:token" minOccurs="1" maxOccurs="unbounded"/>
    <xsd:element name="details" type="xsd:token" minOccurs="1" maxOccurs="unbounded"/>
</xsd:sequence>

匹配的 xml 将是:

<Element>
  <name>e1</name>
  <name>e2</name>
  <name>e3</name>
  <number>n1</number>
  <number>n2</number>
  <number>n3</number>
  <details>i1</details>
  <details>i2</details>
  <details>i3</details>
</Element>

但是当我将以下 xsd 文件转换为 C# 类时(使用 xsd.exe)

<xsd:element name="Element" type="ElementType"/>
  <xsd:complexType name="ElementType">
    <xsd:sequence minOccurs="1" maxOccurs="unbounded">
      <xsd:element name="name" type="xsd:token"/>
      <xsd:element name="number" type="xsd:token"/>
      <xsd:element name="details" type="xsd:token"/>
    </xsd:sequence>
  </xsd:complexType>

生成的 C# 类:

public partial class ElementType

    private string[] nameField;

    private string[] numberField;

    private string[] detailsField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("name", DataType="token")]
    public string[] name
        get 
            return this.nameField;
        
        set 
            this.nameField= value;
        
    

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("number", DataType="token")]
    public string[] number 
        get 
            return this.numberField;
        
        set 
            this.numberField = value;
        
    

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("details", DataType="token")]
    public string[] details
        get 
            return this.detailsField;
        
        set 
            this.detailsField= value;
        
    

我得到了这个 xml(基于 XmlSerializer 的类生成)

<Element>
  <name>e1</name>
  <name>e2</name>
  <name>e3</name>
  <number>n1</number>
  <number>n2</number>
  <number>n3</number>
  <details>i1</details>
  <details>i2</details>
  <details>i3</details>
</Element>

有没有办法生成正确的xml? 或者如果这只是微软XmlSerializer 的工作方式,我需要如何修改 C# 类以获得正确的结果?

【问题讨论】:

微软按照类中属性的顺序进行序列化。因此,如果您有一个数组 string[] 名称,则 xml 中的名称数组将按顺序出现。 @jdweng 我明白了,但这是我在这里的固定要求。所以我的问题是:有没有办法得到预期的结果?可能没有办法编辑生成的 XML ......因为我猜 C# 中没有等效的元素可以做到这一点。 【参考方案1】:

使用客户序列化器:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.Linq;
using System.Xml.Schema;

namespace ConsoleApplication111

    class Program
    
        const string INPUT_FILENAME = @"c:\temp\test.xml";
        const string OUTPUT_FILENAME = @"c:\temp\test1.xml";
        static void Main(string[] args)
        
            XmlReader reader = XmlReader.Create(INPUT_FILENAME);
            XmlSerializer serializer = new XmlSerializer(typeof(ElementType));
            ElementType elementType = (ElementType)serializer.Deserialize(reader);

            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            XmlWriter writer = XmlWriter.Create (OUTPUT_FILENAME, settings);
            serializer.Serialize(writer, elementType);
        
    
    [XmlRoot("Element")]
    public partial class ElementType : IXmlSerializable
    

        private string[] nameField;

        private string[] numberField;

        private string[] detailsField;

        /// <remarks/>
        [XmlElement(ElementName = "name", DataType = "token")]
        public string[] name
        
            get
            
                return this.nameField;
            
            set
            
                this.nameField = value;
            
        

        /// <remarks/>
        [XmlElement(ElementName = "number", DataType = "token")]
        public string[] number
        
            get
            
                return this.numberField;
            
            set
            
                this.numberField = value;
            
        

        /// <remarks/>
        [XmlElement(ElementName = "details", DataType = "token")]
        public string[] details
        
            get
            
                return this.detailsField;
            
            set
            
                this.detailsField = value;
            
        

        public void ReadXml(XmlReader reader)
        
            XElement elementType = XElement.Load(reader);
            nameField = elementType.Elements("name").Select(x => (string)x).ToArray();
            numberField = elementType.Elements("number").Select(x => (string)x).ToArray();
            detailsField = elementType.Elements("details").Select(x => (string)x).ToArray();

        
        public void WriteXml(XmlWriter writer)
        
            int count = nameField.Count();
            XElement element = new XElement("Element");
            for(int i = 0; i < count; i++)
            
                element.Add(new XElement("name", name[i]));
                element.Add(new XElement("number", number[i]));
                element.Add(new XElement("details", detailsField[i]));

            
            writer.WriteRaw(element.ToString());
        


        public XmlSchema GetSchema()
        
            return (null);
        
    

【讨论】:

以上是关于XmlSerializer 生成错误顺序的重复序列的主要内容,如果未能解决你的问题,请参考以下文章

XMLSerializer 不反序列化 XML

C# XMLSerializer 将错误的类型反序列化为 List

无法使用 c# xmlserializer 反序列化以前序列化的 XML

XmlSerializer c++ 使用多个命名空间反序列化

Younge学习.NET反序列化漏洞

XmlSerializer:反序列化递归对象图