如何在层级复杂的XML中根据Var/Value获取对应Supplier/Name值?
问题描述
处理结构怪异的XML文档(缺少ID、命名模糊,嵌套层级超10层),需求:
- 找到
Var/Value为CLR-111的节点 - 向上查找对应的
Supplier/Name节点值(预期返回ACME)
尝试用XmlDocument.SelectSingleNode无法正确向上定位节点,纠结选择LINQ还是XmlDocument实现。
示例XML
<?xml version="1.0" encoding="utf-8"?> <Uni> <Job ID="Job1"> <Manufacturing ID="MPG-1"> <Factory> <SKUGroups ID="SKU-72"> <Supplier> <Name>ACME</Name> <Details address="123 Bobs Road" Zip="90210" /> </Supplier> <Type>Paint</Type> <Var> <Name>ColorID</Name> <Value>CLR-111</Value> </Var> <Supplier> <Name>TomInc</Name> <Details address="555 Jayne Lane" Zip="65986" /> </Supplier> <Type>Tire</Type> <Var> <Name>ColorID</Name> <Value>CLR-2222</Value> </Var> </SKUGroups> </Factory> </Manufacturing> </Job> </Uni>
现有代码
XmlDocument doc = new XmlDocument(); doc.PreserveWhitespace = true; doc.Load(myPath); XmlNode blaa = doc.SelectSingleNode("descendant::SKUGroups[Var/Value='CLR-111']/Var/Name");
解决方案
方案一:XmlDocument(优化XPath)
核心是调整XPath逻辑,直接定位目标Var节点的前置Supplier:
简化XPath查询
XmlDocument doc = new XmlDocument(); doc.Load(myPath); // 直接获取目标Var节点之前的最后一个Supplier的Name XmlNode supplierName = doc.SelectSingleNode("descendant::Var[Value='CLR-111']/preceding-sibling::Supplier[last()]/Name"); if (supplierName != null) { string result = supplierName.InnerText; // 结果为ACME }
分步导航(可读性更强)
如果XPath表达式过于复杂,可拆分步骤:
XmlDocument doc = new XmlDocument(); doc.Load(myPath); // 1. 定位到Value为CLR-111的Var节点 XmlNode targetVar = doc.SelectSingleNode("descendant::Var[Value='CLR-111']"); if (targetVar == null) return; // 2. 找到该Var节点之前的最后一个Supplier节点 XmlNode supplier = targetVar.SelectSingleNode("preceding-sibling::Supplier[last()]"); if (supplier == null) return; // 3. 获取Name值 string result = supplier.SelectSingleNode("Name").InnerText;
方案二:LINQ to XML(推荐)
LINQ to XML的节点导航更直观,适合复杂层级的文档,逻辑清晰易维护:
XDocument doc = XDocument.Load(myPath); // 找到Value为CLR-111的Var节点 var targetVar = doc.Descendants("Var") .FirstOrDefault(v => v.Element("Value")?.Value == "CLR-111"); if (targetVar == null) return; // 获取该Var节点之前的最后一个Supplier的Name值 string result = targetVar .ElementsBeforeSelf("Supplier") .LastOrDefault()? .Element("Name")? .Value; // 结果为ACME
方案对比
- XmlDocument:适合熟悉XPath的场景,代码简洁,但复杂结构下XPath可读性差,调试难度高。
- LINQ to XML:链式调用逻辑直观,节点导航灵活,维护成本低,尤其适合嵌套层级深的文档,优先推荐。
内容的提问来源于stack exchange,提问作者Cyberdrac
相关产品推荐
相关产品推荐

