在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>
序列化后。
如果这个解决方案也适用于反序列化,那将是令人惊讶的。
如果您真的必须避免"改变类结构",属性(在我看来)不会得到您想要的XML结构,和帮助您获得可读、可维护的代码。
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
的使用,而根本不改变类结构。
您可以通过为每个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; }
}
在线演示