如何用序列化特性将固定ID的XML列表反序列化为指定C#类?
问题描述
给定以下XML:
<Values> <Value ID="Foo">foo</Value> <Value ID="Bar">42</Value> </Values>
已知ID列表固定不变,请问如何使用序列化特性将其解析为如下C#类?
public class Values { public string Foo { get; set; } public int Bar { get; set; } }
直接解析为数组的方法虽然简单,但验证和读取值时非常繁琐,当前实现代码如下:
[Serializable] public class Values { [XmlElement("Values")] public Value[]? Values { get; init; } } [Serializable] public class Value { [XmlAttribute("ID")] public string? Id { get; init; } [XmlText] public string? Value { get; init; } }
解决方案
可以通过实现IXmlSerializable接口自定义序列化和反序列化逻辑,直接将XML中的Value元素按ID映射到目标类的属性上,具体实现如下:
using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; public class Values : IXmlSerializable { public string Foo { get; set; } = string.Empty; public int Bar { get; set; } public XmlSchema? GetSchema() => null; public void ReadXml(XmlReader reader) { // 跳过根元素开始标签 reader.ReadStartElement("Values"); while (reader.NodeType != XmlNodeType.EndElement) { if (reader.Name == "Value") { var id = reader.GetAttribute("ID"); var valueContent = reader.ReadElementContentAsString(); switch (id) { case "Foo": Foo = valueContent; break; case "Bar": if (int.TryParse(valueContent, out var barVal)) { Bar = barVal; } break; } } else { // 跳过未知节点 reader.Skip(); } } // 读取根元素结束标签 reader.ReadEndElement(); } public void WriteXml(XmlWriter writer) { // 生成Foo对应的Value元素 writer.WriteStartElement("Value"); writer.WriteAttributeString("ID", "Foo"); writer.WriteString(Foo); writer.WriteEndElement(); // 生成Bar对应的Value元素 writer.WriteStartElement("Value"); writer.WriteAttributeString("ID", "Bar"); writer.WriteString(Bar.ToString()); writer.WriteEndElement(); } }
使用示例
// 反序列化示例 var xmlContent = @"<Values> <Value ID=""Foo"">foo</Value> <Value ID=""Bar"">42</Value> </Values>"; var serializer = new XmlSerializer(typeof(Values)); using var reader = new StringReader(xmlContent); var valuesObj = (Values)serializer.Deserialize(reader)!; Console.WriteLine(valuesObj.Foo); // 输出: foo Console.WriteLine(valuesObj.Bar); // 输出: 42 // 序列化示例 var newValues = new Values { Foo = "newFoo", Bar = 100 }; using var writer = new StringWriter(); serializer.Serialize(writer, newValues); Console.WriteLine(writer.ToString()); // 输出符合原格式的XML
这种方式完全自定义了序列化逻辑,既满足了XML到目标类的映射需求,又避免了数组方式的繁琐操作,且因ID固定,逻辑清晰易维护。
内容的提问来源于stack exchange,提问作者Jakube
相关产品推荐
相关产品推荐

