繁体   English   中英

在序列化期间将组 c# class 属性分组到 XmlElement 属性中

[英]Group group c# class properties into XmlElement attributes during serialization

During the serialization of c# classes into xml, I need to match a certain xml structure, but it would be for the best not to alter the class structure already present.

是否可以将许多属性的某种分组创建到它们自己的 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 output :

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

序列化后。

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

您可以通过为每个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; }
}

在线演示

如果您真的必须避免“更改 class 结构”,属性(在我看来)不会获得您想要的 XML 结构,帮助您获得可读、可维护的代码。

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

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

正如您将看到的,编写比使用属性更麻烦。 但是一旦你掌握了它,它就会变得非常简单。 它绝对不会改变 class 结构。

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的使用而不改变 class 结构。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM