【问题标题】:Group group c# class properties into XmlElement attributes during serialization在序列化期间将组 c# 类属性分组到 XmlElement 属性中
【发布时间】:2021-05-29 08:01:12
【问题描述】:

在将c#类序列化为xml的过程中,我需要匹配某个xml结构,但最好不要改变已经存在的类结构。

是否可以创建一种将许多属性分组到它们自己的 xml 元素中,并将它们的值存储为 xml 属性的地方?

示例 C# 代码类似于:

class SomeClass {
    [XmlElement("Element1")]
    [XmlAttribute("attribute1")]
    int prop1;
    [XmlElement("Element1")]
    [XmlAttribute("attribute2")]
    int prop2;

    [XmlElement("Element2")]
    [XmlAttribute("attribute1")]
    int prop3;
    [XmlElement("Element2")]
    [XmlAttribute("attribute2")]
    int prop4;
    [XmlElement("Element2")]
    [XmlAttribute("attribute3")]
    int prop5;
    [XmlElement("Element2")]
    [XmlAttribute("attribute4")]
    int prop6;
}

使用 xml 输出:

<SomeClass>
    <Element1 Attribute1="value1" attribute2="value2"/>
    <Element2 Attribute1="value3" attribute2="value4" attribute3="value5" attribute4="value6"/>
</SomeClass>

序列化后。

如果该解决方案也适用于反序列化,那就太棒了。

【问题讨论】:

    标签: c# xml serialization xmlelement


    【解决方案1】:

    如果你真的必须避免“改变类结构”,属性(在我看来)不会获得你想要的 XML 结构并且帮助你获得可读、可维护的代码。 p>

    IXmlSerializable 接口允许您手动控制类的序列化/反序列化。实现此接口时,您可以完全控制在 XmlSerializer 使用您的类时创建所需的任何 XML 文本。

    下面是一个编译控制台应用程序示例供您使用。它展示了如何在您的SomeClass XML 中读取和写入自定义节点,并将您的类属性放入这些节点上的 XML 属性中。请注意,我使用 nameof 来获取属性名称,但如果需要,您也可以轻松地将 XML 属性名称硬编码为 "Attribute1""Attribute2"

    如您所见,编写比使用属性更麻烦。但是一旦你掌握了它,它就会变得非常简单。而且绝对不会改变类结构。

    using System.IO;
    using System.Xml;
    using System.Xml.Schema;
    using System.Xml.Serialization;
    
    namespace ConsoleApp1
    {
        public class SomeClass : IXmlSerializable
        {
            // element 1
            public int prop1 { get; set; }
            public int prop2 { get; set; }
    
            // element 2
            public int prop3 { get; set; }
            public int prop4 { get; set; }
            public int prop5 { get; set; }
            public int prop6 { get; set; }
    
            #region IXmlSerializable
            public XmlSchema GetSchema()
            {
                return null;
            }
    
            public void WriteXml(XmlWriter writer)
            {
                writer.WriteStartElement("Element1");
                writer.WriteAttributeString(nameof(prop1), prop1.ToString());
                writer.WriteAttributeString(nameof(prop2), prop2.ToString());
                writer.WriteEndElement();
    
                writer.WriteStartElement("Element2");
                writer.WriteAttributeString(nameof(prop3), prop3.ToString());
                writer.WriteAttributeString(nameof(prop4), prop4.ToString());
                writer.WriteAttributeString(nameof(prop5), prop5.ToString());
                writer.WriteAttributeString(nameof(prop6), prop6.ToString());
                writer.WriteEndElement();
            }
    
            public void ReadXml(XmlReader reader)
            {
                // element 1
                reader.Read();
                reader.MoveToAttribute(nameof(prop1));
                if (reader.ReadAttributeValue())
                {
                    prop1 = int.Parse(reader.Value);
                }
                reader.MoveToAttribute(nameof(prop2));
                if (reader.ReadAttributeValue())
                {
                    prop2 = int.Parse(reader.Value);
                }
    
                // element 2
                reader.Read();
                reader.MoveToAttribute(nameof(prop3));
                if (reader.ReadAttributeValue())
                {
                    prop3 = int.Parse(reader.Value);
                }
                reader.MoveToAttribute(nameof(prop4));
                if (reader.ReadAttributeValue())
                {
                    prop4 = int.Parse(reader.Value);
                }
                reader.MoveToAttribute(nameof(prop5));
                if (reader.ReadAttributeValue())
                {
                    prop5 = int.Parse(reader.Value);
                }
                reader.MoveToAttribute(nameof(prop6));
                if (reader.ReadAttributeValue())
                {
                    prop6 = int.Parse(reader.Value);
                }
            }
            #endregion
        }
    
        class Program
        {
            static void Main()
            {
                string tempPath = "c:\\temp\\test.xml";
                XmlSerializer serializer = new XmlSerializer(typeof(SomeClass));
    
                // build an instance to serialize
                SomeClass s1 = new SomeClass
                {
                    prop1 = 1,
                    prop2 = 2,
                    prop3 = 3,
                    prop4 = 4,
                    prop5 = 5,
                    prop6 = 6
                };
    
                // serialize it
                using (StreamWriter sw = new StreamWriter(tempPath))
                {
                    serializer.Serialize(sw, s1);
    
                }
    
                /* Produces the following XML:
                    <?xml version="1.0" encoding="utf-8"?>
                    <SomeClass>
                      <Element1 prop1="1" prop2="2" />
                      <Element2 prop3="3" prop4="4" prop5="5" prop6="6" />
                    </SomeClass>
                */
    
                // deserialize
                SomeClass s2;
                using (StreamReader sr = new StreamReader(tempPath))
                {
                    s2 = (SomeClass)serializer.Deserialize(sr);
                }
    
                // check contents of s2 as you please
            }
        }
    }
    

    (如果你喜欢这个,你应该在实际部署之前清理它 - 不存在错误处理,例如在int.Parse 上。它只是为了说明IXmlSerializable 的使用,根本不改变类结构.)

    【讨论】:

      【解决方案2】:

      您可以通过为每个 XmlElement 使用单独的类来做到这一点:

      public class SomeClass 
      {
          public Element1 Element1 { get; set; }
          
          public Element2 Element2 { get; set; }
      }
      
      public class Element1 
      {
          [XmlAttribute]
          public int attribute1 { get; set; }
      
          [XmlAttribute]
          public int attribute2 { get; set; }
      }
      
      public class Element2
      {
          [XmlAttribute]
          public int attribute1 { get; set; }
      
          [XmlAttribute]
          public int attribute2 { get; set; }
          
          [XmlAttribute]
          public int attribute3 { get; set; }
      
          [XmlAttribute]
          public int attribute4 { get; set; }
      }
      

      Online demo

      【讨论】:

        猜你喜欢
        • 2011-02-10
        • 1970-01-01
        • 1970-01-01
        • 2020-01-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多