不使用Linq-to-XML,能否通过System.Xml.Serialization将XML反序列化为字典?
仅用System.Xml.Serialization属性实现XML到字典结构的反序列化
待反序列化的XML
<MessageList category="Alarm" version="1.0.0"> <Item id="1"> <Message key="Level" text="Alarm" /> <Message key="Title" text="ERROR AT PLC UNIT" /> <Message key="Detail" text="Change PLC unit. 
If it is out of order. please contact our service man." /> </Item> <Item id="2"> <Message key="Level" text="Alarm" /> <Message key="Title" text="RE-SET PLC UNIT ( PROGRAM FS )" /> <Message key="Detail" text="Turn off and restart. if the problem persists. check thet the switch on the controller is in RUN mode. 
If it is out of order. please contact our service man." /> </Item> <Item id="3"> <Message key="Level" text="Alarm" /> <Message key="Title" text="" /> <Message key="Detail" text="" /> </Item> <Item id="4"> <Message key="Level" text="Alarm" /> <Message key="Title" text="" /> <Message key="Detail" text="" /> </Item> <Item id="5"> <Message key="Level" text="Alarm" /> <Message key="Title" text="" /> <Message key="Detail" text="" /> </Item> </MessageList>
期望的类结构
class MessageListClass { public string category { get; set; } public string version { get; set; } public Dictionary<int, List<Message>> items { get; set; } } public class Message { public string key { get; set; } public string text { get; set; } }
当前可运行的非字典版本代码
[XmlRoot("MessageList")] class MessageList { [XmlAttribute("category")] public string category { get; set; } [XmlAttribute("version")] public string version { get; set; } [XmlElement("Item")] public List<Item> items { get; set; } } public class Item { [XmlAttribute("id")] public int alarmId { get; set; } [XmlElement("Message")] public List<Message> messages { get; set; } } public class Message { [XmlAttribute("key")] public string key { get; set; } [XmlAttribute("text")] public string text { get; set; } }
问题
是否可以不使用Linq-to-XML,仅通过System.Xml.Serialization属性实现上述字典形式的反序列化?
解决方案
可以通过代理属性结合XmlIgnore和XmlElement属性实现,无需Linq-to-XML。核心思路是用可序列化的List<ItemProxy>作为中转,在序列化/反序列化时自动完成与字典结构的转换。
修改后的完整代码
[XmlRoot("MessageList")] public class MessageListClass { [XmlAttribute("category")] public string category { get; set; } [XmlAttribute("version")] public string version { get; set; } // 目标字典,标记为XmlIgnore跳过直接序列化 [XmlIgnore] public Dictionary<int, List<Message>> items { get; set; } = new Dictionary<int, List<Message>>(); // 代理属性,对应XML中的<Item>节点集合 [XmlElement("Item")] public List<ItemProxy> ItemProxies { get { // 字典转代理列表,供序列化输出 return items.Select(kv => new ItemProxy { id = kv.Key, messages = kv.Value }).ToList(); } set { // 代理列表转字典,完成反序列化赋值 items = value.ToDictionary(item => item.id, item => item.messages); } } // 内部代理类,完全匹配XML中<Item>的结构 public class ItemProxy { [XmlAttribute("id")] public int id { get; set; } [XmlElement("Message")] public List<Message> messages { get; set; } = new List<Message>(); } } public class Message { [XmlAttribute("key")] public string key { get; set; } [XmlAttribute("text")] public string text { get; set; } }
代码说明
XmlIgnore标记目标字典:让items字典不直接参与XML序列化流程,避免序列化器无法识别字典类型的问题。- 代理属性
ItemProxies:用XmlElement("Item")标记,与XML中的<Item>节点一一对应,负责接收和输出XML结构。 - 双向转换逻辑:
get方法:将字典中的键值对转换为ItemProxy列表,适配XML序列化的格式要求。set方法:将反序列化得到的ItemProxy列表转换为字典结构,赋值给目标items属性。
ItemProxy类:完全映射XML中<Item>节点的结构,包含id属性和Message列表,保证序列化/反序列化的正确性。
反序列化测试示例
using System.Xml.Serialization; using System.IO; // 读取XML文件内容 string xmlContent = File.ReadAllText("alarm-messages.xml"); // 创建序列化器 XmlSerializer serializer = new XmlSerializer(typeof(MessageListClass)); // 执行反序列化 using (StringReader reader = new StringReader(xmlContent)) { MessageListClass result = (MessageListClass)serializer.Deserialize(reader); // result.items即为目标字典结构,可直接按id索引访问对应Message列表 }
内容的提问来源于stack exchange,提问作者Cominoda
相关产品推荐
相关产品推荐

