使用XPath遍历XML节点存储定罪代码的问题排查
问题原因分析与解决方案
常见错误原因
- XPath查询未限定范围:如果每次查询
conviction节点时,都是基于整个XML文档而非当前遍历的proposer/driver节点,就会反复获取文档中第一个conviction的code值,导致重复。 - 变量赋值逻辑错误:比如循环中未正确获取当前节点的code值,而是一直复用之前的变量值,最终列表里存的都是同一个重复值。
典型错误代码示例
假设你的代码是类似这样的(核心错误点已标注):
List<string> convictionCodes = new List<string>(); XmlDocument doc = new XmlDocument(); doc.Load("yourFile.xml"); XmlNodeList proposers = doc.SelectNodes("//proposer"); foreach (XmlNode proposer in proposers) { // ❌ 错误:未限定在当前proposer节点下,会取整个文档的第一个conviction string code = doc.SelectSingleNode("//conviction/@code").Value; convictionCodes.Add(code); } XmlNodeList drivers = doc.SelectNodes("//driver"); foreach (XmlNode driver in drivers) { // ❌ 同样的错误,重复获取第一个conviction的code string code = doc.SelectSingleNode("//conviction/@code").Value; convictionCodes.Add(code); } // 输出结果自然会重复第一个值 Console.WriteLine($"DrivingConvictionCode1={convictionCodes[0]}"); Console.WriteLine($"DrivingConvictionCode2={convictionCodes[1]}"); Console.WriteLine($"DrivingConvictionCode3={convictionCodes[2]}");
解决方案
方案1:限定XPath查询范围到当前节点
遍历proposer/driver节点时,使用当前节点的SelectSingleNode方法,XPath以.开头,表示从当前节点开始查询子节点:
List<string> convictionCodes = new List<string>(); XmlDocument doc = new XmlDocument(); doc.Load("yourFile.xml"); // 处理proposer节点下的conviction foreach (XmlNode proposer in doc.SelectNodes("//proposer")) { XmlNode conviction = proposer.SelectSingleNode(".//conviction"); if (conviction?.Attributes["code"] != null) { convictionCodes.Add(conviction.Attributes["code"].Value); } } // 处理driver节点下的conviction foreach (XmlNode driver in doc.SelectNodes("//driver")) { XmlNode conviction = driver.SelectSingleNode(".//conviction"); if (conviction?.Attributes["code"] != null) { convictionCodes.Add(conviction.Attributes["code"].Value); } } // 输出期望结果 if (convictionCodes.Count >= 3) { Console.WriteLine($"DrivingConvictionCode1={convictionCodes[0]}"); Console.WriteLine($"DrivingConvictionCode2={convictionCodes[1]}"); Console.WriteLine($"DrivingConvictionCode3={convictionCodes[2]}"); }
方案2:一次性查询所有符合条件的节点
用XPath的或逻辑,直接获取所有proposer和driver下的conviction的code属性,简化代码:
List<string> convictionCodes = new List<string>(); XmlDocument doc = new XmlDocument(); doc.Load("yourFile.xml"); // 一次性获取所有目标code属性节点 XmlNodeList codeNodes = doc.SelectNodes("//proposer//conviction/@code | //driver//conviction/@code"); foreach (XmlNode codeNode in codeNodes) { convictionCodes.Add(codeNode.Value); } // 输出结果 if (convictionCodes.Count >= 3) { Console.WriteLine($"DrivingConvictionCode1={convictionCodes[0]}"); Console.WriteLine($"DrivingConvictionCode2={convictionCodes[1]}"); Console.WriteLine($"DrivingConvictionCode3={convictionCodes[2]}"); }
方案3:使用LINQ to XML(更简洁可靠)
如果你的项目基于.NET Framework 3.5及以上,推荐使用LINQ to XML,代码更简洁且不易出错:
XDocument doc = XDocument.Load("yourFile.xml"); List<string> convictionCodes = doc.Descendants() .Where(node => node.Name == "proposer" || node.Name == "driver") .Descendants("conviction") .Select(conv => conv.Attribute("code")?.Value) .Where(code => !string.IsNullOrEmpty(code)) .ToList(); // 输出结果 if (convictionCodes.Count >= 3) { Console.WriteLine($"DrivingConvictionCode1={convictionCodes[0]}"); Console.WriteLine($"DrivingConvictionCode2={convictionCodes[1]}"); Console.WriteLine($"DrivingConvictionCode3={convictionCodes[2]}"); }
内容的提问来源于stack exchange,提问作者Pratex
相关产品推荐
相关产品推荐

