如何智能将指定结构XML解析为List<MyObject>,无需逐节点解析?
问题
我有如下结构的XML文件:
<?xml version="1.0"?> <myobjectlist objectCount = "3"> <myobject Number = "0" Name="My First Object" MyChildObectsCount = "2"> <intProp>5</intProp> <stringProp>Str1</stringProp> <doubleProp>35.1</doubleProp> <MyChildObj Number = "100" Name = "My first child object"> <childIntProp>1</childIntProp> <childStringProp>CStr1</childStringProp> </MyChildObj> <MyChildObj Number = "120" Name = "My child object"> <childIntProp>15</childIntProp> <childStringProp>CStr2</childStringProp> </MyChildObj> </myobject> <myobject Number = "145" Name="My second Object" MyChildObectsCount = "1"> <intProp>96</intProp> <stringProp>Str2</stringProp> <doubleProp>+Inf</doubleProp> <MyChildObj Number = "250" Name = "This's child object"> <childIntProp>62</childIntProp> <childStringProp>CStr3</childStringProp> </MyChildObj> </myobject> <myobject Number = "261" Name="My last Object" MyChildObectsCount = "3"> <intProp>9</intProp> <stringProp>Str45</stringProp> <doubleProp>1.6449635e+07</doubleProp> <MyChildObj Number = "150" Name = "Almost last child object"> <childIntProp>-1</childIntProp> <childStringProp>CStr41</childStringProp> </MyChildObj> <MyChildObj Number = "680" Name = "Prelast child object"> <childIntProp>72</childIntProp> <childStringProp>CStr42</childStringProp> </MyChildObj> <MyChildObj Number = "127" Name = "Last child object"> <childIntProp>64</childIntProp> <childStringProp>CStr222</childStringProp> </MyChildObj> </myobject> </myobjectlist>
我曾尝试使用XMLSerializer进行反序列化,但发现它无法正确反序列化为列表,得到的结果列表中所有对象都是XML的第一个对象,列表元素总数等于XML内对象总数,后续操作还出现了返回空列表的问题。
我已经创建了对应XML对象的实体类,代码如下:
public class MyObject{ int Number; string Name; int IntProp; string stringProp; double doubleProp; List<MyChildObject> myChildObjects; } public class MyChildObject{ int Number; string Name; int childIntProp; string childStringProp; }
我需要从该XML文件中获取List<MyObject>类型的结果,且不想逐节点手动解析,请问有什么智能的实现方法?
更新说明
当前我执行操作得到的结果为空列表。
解决方案
你遇到的问题本质是XmlSerializer的映射规则不匹配,核心问题有两个:一是你的实体类成员都是私有字段,序列化器没有访问权限;二是没有显式配置XML节点和实体类的映射关系,导致名称不匹配时无法正确赋值。
按以下步骤修改即可直接反序列化得到目标结果:
步骤1:修正实体类,添加映射特性
using System.Collections.Generic; using System.Xml.Serialization; // 映射XML根节点myobjectlist [XmlRoot("myobjectlist")] public class MyObjectListRoot { [XmlAttribute("objectCount")] public int ObjectCount { get; set; } // 直接映射根节点下所有名为myobject的子节点到集合 [XmlElement("myobject")] public List<MyObject> MyObjects { get; set; } } public class MyObject { [XmlAttribute("Number")] public int Number { get; set; } [XmlAttribute("Name")] public string Name { get; set; } [XmlAttribute("MyChildObectsCount")] public int MyChildObjectsCount { get; set; } [XmlElement("intProp")] public int IntProp { get; set; } [XmlElement("stringProp")] public string StringProp { get; set; } [XmlElement("doubleProp")] public double DoubleProp { get; set; } // 映射当前节点下所有名为MyChildObj的子节点到集合 [XmlElement("MyChildObj")] public List<MyChildObject> MyChildObjects { get; set; } } public class MyChildObject { [XmlAttribute("Number")] public int Number { get; set; } [XmlAttribute("Name")] public string Name { get; set; } [XmlElement("childIntProp")] public int ChildIntProp { get; set; } [XmlElement("childStringProp")] public string ChildStringProp { get; set; } }
步骤2:编写反序列化逻辑
using System.IO; using System.Xml.Serialization; public List<MyObject> GetMyObjectsFromXml(string xmlFilePath) { var serializer = new XmlSerializer(typeof(MyObjectListRoot)); using (var streamReader = new StreamReader(xmlFilePath)) { var root = (MyObjectListRoot)serializer.Deserialize(streamReader); return root.MyObjects; } }
注意事项
- 所有需要反序列化的成员必须声明为
public的属性,且同时包含get和set方法,私有字段无法被XmlSerializer赋值 - 用
[XmlAttribute]标记对应XML节点属性的属性,用[XmlElement]标记对应XML子元素的属性,避免大小写、命名差异导致的映射失败 - 如果集合的子节点没有额外的父容器包裹,直接给集合属性加
[XmlElement("子节点名")]即可,不需要额外定义容器类
内容的提问来源于stack exchange,提问作者dragondangun
相关产品推荐
相关产品推荐

