使用C# XML序列化器生成自定义XML格式

3
我是一名初学者,正在使用Visual Studio 2013,并尝试使用C# XML序列化器/反序列化器将存储在类中的变量转换为XML文件。
给定一个简单的类:
public class TestXML
{
    public String Label = "Hello";
    public Boolean Enable = true;
    public Int32 PosX = 12;
    public Int32 PosY = 34;
}

默认情况下,序列化器以以下形式生成XML:
<TestXML>
  <Label>Hello</Label>
  <Enable>true</Enable>
  <PosX>12</PosX>
  <PosY>34</PosY>
</TestXML>

很不幸,我的项目要求XML文件中的参数必须按照以下格式进行格式化:
<TestXML>
  <model>
    <prop name="Label" value="Hello" />
    <prop name="Enable" value="true" />
    <prop name="PosX" value="12" />
    <prop name="PosY" value="34" />
  </model>
</TestXML>

我一直在研究如何使用XmlAttributeXmlElement选项来控制XML格式,但是我没有找到任何方法来生成所需的格式。是否有办法让序列化器以这种特定的格式存储变量?

4个回答

4

根据king.code的答案手动控制序列化是一种选择(因此我不会重复)。另一种选择是以不同的方式构造您的模型,或者如果不是选项,则创建另一个“数据模型”,将现有模型映射到该模型并对其进行序列化。这可能比大量低级XmlReader / XmlWriter代码更容易。

要获得您想要的结果,您需要像这样:

public class TestXml
{
    [XmlArray("model")]
    [XmlArrayItem("prop")]
    public List<Prop> Props { get; set; }
}


public class Prop
{
    [XmlAttribute("name")]
    public string Name { get; set; }

    [XmlAttribute("value")]
    public string Value { get; set; }
}

这篇内容:

var xml = new TestXml
{
    Props = new List<Prop>
    {
        new Prop
        {
            Name = "Label",
            Value = "Hello"
        }
    }
};

然后序列化为以下内容:
<TestXML>
  <model>
    <prop name="Label" value="Hello" />
  </model>
</TestXML>

2

使用XmlAttributeAttribute无法实现该功能。建议实现IXmlSerializable接口。

public class TestXML : IXmlSerializable
{
    public String Label = "Hello";
    public Boolean Enable = true;
    public Int32 PosX = 12;
    public Int32 PosY = 34;

    public void WriteXml(XmlWriter writer)
    {
        // Serialize
    }

    public void ReadXml(XmlReader reader)
    {
        // Deserialize
    }

    public XmlSchema GetSchema()
    {
        return null;
    }
}

通过这种方式,您可以完全控制您的XML的形状。您可以在此处找到所有序列化/反序列化类所需的信息


1
这只能通过实现 IXmlSerializable 接口来完成,该接口允许您自定义 XML 的形状。
public class TestXML : IXmlSerializable
{
    public String Label = "Hello";
    public Boolean Enable = true;
    public Int32 PosX = 12;
    public Int32 PosY = 34;

    XmlSchema IXmlSerializable.GetSchema()
    {
        return null;
    }

    void IXmlSerializable.ReadXml(XmlReader reader)
    {
        reader.ReadStartElement();
        reader.ReadStartElement("model");

        if (reader.Name != "prop")
        { throw new InvalidOperationException(); }

        do
        {
            if (!reader.MoveToAttribute("name"))
            { throw new InvalidOperationException(); }

            string name = reader.Value;

            if (!reader.MoveToAttribute("value"))
            { throw new InvalidOperationException(); }

            switch (name)
            {
                case "Label": Label = reader.Value; break;
                case "Enable": Enable = XmlConvert.ToBoolean(reader.Value); break;
                case "PosX": PosX = XmlConvert.ToInt32(reader.Value); break;
                case "PosY": PosY = XmlConvert.ToInt32(reader.Value); break;
            }
        }
        while (reader.ReadToNextSibling("prop"));

        reader.ReadEndElement();
        reader.ReadEndElement();
    }

    void IXmlSerializable.WriteXml(XmlWriter writer)
    {
        writer.WriteStartElement("model");
        WriteProperty(writer, "Label", Label);
        WriteProperty(writer, "Enable", XmlConvert.ToString(Enable));
        WriteProperty(writer, "PosX", XmlConvert.ToString(PosX));
        WriteProperty(writer, "PosY", XmlConvert.ToString(PosY));
        writer.WriteEndElement();
    }

    private void WriteProperty(XmlWriter writer, string name, string value)
    {
        writer.WriteStartElement("prop");
        writer.WriteAttributeString("name", name);
        writer.WriteAttributeString("value", value);
        writer.WriteEndElement();
    }
}

链接:

  1. IXmlSerializable接口
  2. 如何正确实现IXmlSerializable接口

感谢您快速而详细的回复。唯一不理想的是需要使用switch语句来处理每个变量名,因为在实际项目中有数十个这样的类,每个类都包含许多变量。似乎每个类都需要自己的定制XML代码来处理变量名 - 是否有任何方法可以使序列化程序自动完成此操作? - Chris Kessell
这是自定义XML格式的缺点。但是你会获得快速的序列化/反序列化和较低的内存消耗,因为不使用额外的类和列表。 - Yoh Deadfall

0

你可以创建三个类:

public class TextXML
{
 public Model model {get; set;}
}
public class Model
{      
 public List<prop> props{get; set;}
}
public class prop
{
public string name{get; set;}
public string value{get; set;}

}

使用XmlAttributes进行序列化。在您的模型类中,使用XmlArray来处理prop类。

如果您有任何进一步的问题,请不要犹豫,我目前正在一个使用大量xml和属性的项目上工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接