如何读取嵌套XML文件并将数据存储到列表中?
嵌套XML数据提取最优实现方案
问题描述
我有一个以int和string类型数据为主的嵌套XML文件,需要将其中的数据提取并存储到列表中供后续使用。此前尝试使用using System.Xml;创建阅读器,通过reader.ReadToFollowing("Something")结合reader.GetAttribute("Id")的方式读取,但无法获取到深层数据;而该方法在简单结构XML(如示例中的Animal结构)中可正常工作,现寻求最优实现方案。
目标XML结构
<AllThings> <Anythings> <Anything Step="1" Name="1"> <Somethings> <Something Id="10"> <Things> <Thing Id="11">abc</Thing> <Thing Id="12">123</Thing> </Things> </Something> <Something Id="20"> <Things> <Thing Id="21">cde</Thing> <Thing Id="22">345</Thing> </Things> </Something> <Something Id="30"> <Things> <Thing Id="31">efg</Thing> <Thing Id="32">567</Thing> </Things> </Something> <Something Id="40"> <Things> <Thing Id="41">ghi</Thing> <Thing Id="42">789</Thing> </Things> </Something> </Somethings> </Anything> <Anything Step="2" Name="2"> <Somethings> <Something Id="10"> <Things> <Thing Id="11">aaa</Thing> <Thing Id="12">111</Thing> </Things> </Something> <Something Id="20"> <Things> <Thing Id="21">ccc</Thing> <Thing Id="22">333</Thing> </Things> </Something> <Something Id="30"> <Things> <Thing Id="31">eee</Thing> <Thing Id="32">555</Thing> </Things> </Something> <Something Id="40"> <Things> <Thing Id="41">ggg</Thing> <Thing Id="42">777</Thing> </Things> </Something> </Somethings> </Anything> </Anythings> </AllThings>
可正常处理的简单XML示例
<Animal type="cat"> <Name>Bob</Name> <Age>8</Age> </Animal>
解决方案
1. 改进XmlReader方式(适合大文件,内存友好)
XmlReader是流式读取,需要手动处理节点嵌套层级。先定义对应数据类,再通过循环遍历节点逐层解析:
// 定义数据类 public class ThingData { public int Step { get; set; } public string Name { get; set; } public int SomethingId { get; set; } public int ThingId { get; set; } public string Value { get; set; } } // 读取逻辑 List<ThingData> thingList = new List<ThingData>(); using (XmlReader reader = XmlReader.Create("your-xml-file-path.xml")) { int currentStep = 0; string currentName = string.Empty; int currentSomethingId = 0; while (reader.Read()) { // 记录当前Anything的Step和Name if (reader.NodeType == XmlNodeType.Element && reader.Name == "Anything") { currentStep = int.Parse(reader.GetAttribute("Step")); currentName = reader.GetAttribute("Name"); } // 记录当前Something的Id else if (reader.NodeType == XmlNodeType.Element && reader.Name == "Something") { currentSomethingId = int.Parse(reader.GetAttribute("Id")); } // 提取Thing节点数据并加入列表 else if (reader.NodeType == XmlNodeType.Element && reader.Name == "Thing") { ThingData data = new ThingData { Step = currentStep, Name = currentName, SomethingId = currentSomethingId, ThingId = int.Parse(reader.GetAttribute("Id")), Value = reader.ReadElementContentAsString() }; thingList.Add(data); } } }
2. LINQ to XML(XDocument)方式(代码简洁,适合中小文件)
通过LINQ查询直接遍历嵌套节点,代码可读性高:
List<ThingData> thingList = new List<ThingData>(); XDocument doc = XDocument.Load("your-xml-file-path.xml"); var query = from anything in doc.Descendants("Anything") let step = int.Parse(anything.Attribute("Step").Value) let name = anything.Attribute("Name").Value from something in anything.Descendants("Something") let somethingId = int.Parse(something.Attribute("Id").Value) from thing in something.Descendants("Thing") select new ThingData { Step = step, Name = name, SomethingId = somethingId, ThingId = int.Parse(thing.Attribute("Id").Value), Value = thing.Value }; thingList = query.ToList();
3. XmlDocument+XPath方式(传统DOM方式)
用XPath定位节点,再向上遍历父节点获取层级数据:
List<ThingData> thingList = new List<ThingData>(); XmlDocument doc = new XmlDocument(); doc.Load("your-xml-file-path.xml"); XmlNodeList thingNodes = doc.SelectNodes("//Thing"); foreach (XmlNode thingNode in thingNodes) { // 向上获取父级节点数据 XmlNode somethingNode = thingNode.ParentNode.ParentNode; XmlNode anythingNode = somethingNode.ParentNode.ParentNode; ThingData data = new ThingData { Step = int.Parse(anythingNode.Attributes["Step"].Value), Name = anythingNode.Attributes["Name"].Value, SomethingId = int.Parse(somethingNode.Attributes["Id"].Value), ThingId = int.Parse(thingNode.Attributes["Id"].Value), Value = thingNode.InnerText }; thingList.Add(data); }
方案选择建议
- 若XML文件体积较大(几百MB以上),优先选XmlReader,流式读取不占用大量内存;
- 若文件体积小,追求代码简洁易维护,选LINQ to XML;
- 若熟悉XPath语法,XmlDocument+XPath也是可行选项。
内容的提问来源于stack exchange,提问作者barth87
相关产品推荐
相关产品推荐

