基于XML的特定LINEXXXDEF节点筛选XPath查询需求
解决方案:正确筛选LINEXXXDEF节点的XPath与C#实现
一、正确的XPath查询
直接用这条XPath就能精准匹配你需要的两类节点,不会误抓非紧邻的节点:
//LINEXXXDEF[ASCMPXXDEF] | //LINEXXXDEF[EXDSCXXDEF][preceding-sibling::LINEXXXDEF[1][ASCMPXXDEF]]
拆分解释:
//LINEXXXDEF[ASCMPXXDEF]:匹配所有包含ASCMPXXDEF子节点的LINEXXXDEF,对应第一类需求。//LINEXXXDEF[EXDSCXXDEF][preceding-sibling::LINEXXXDEF[1][ASCMPXXDEF]]:只匹配两种条件同时满足的节点:自身带EXDSCXXDEF子节点,且紧挨着它的前一个兄弟节点是带ASCMPXXDEF的LINEXXXDEF。这里的[1]是关键,确保只看紧邻的前一个,而非任意前面的节点,彻底避免误匹配lineno=7这类不符合紧邻要求的节点。
二、C#代码处理方案
如果用C#处理,下面两种常用方式都能实现需求:
1. LINQ to XML(XDocument)写法
这种方式代码更简洁灵活,适合.NET Core/.NET 5+环境:
using System; using System.Linq; using System.Xml.Linq; class XmlNodeFilter { static void Main() { // 替换为你的XML文件路径或直接加载XML字符串 XDocument xmlDoc = XDocument.Load("target.xml"); // 筛选第一类节点:包含ASCMPXXDEF的LINEXXXDEF var firstCategory = xmlDoc.Descendants("LINEXXXDEF") .Where(node => node.Elements("ASCMPXXDEF").Any()); // 筛选第二类节点:紧跟第一类节点之后,且包含EXDSCXXDEF的LINEXXXDEF var secondCategory = xmlDoc.Descendants("LINEXXXDEF") .Where(node => node.Elements("EXDSCXXDEF").Any() && node.PreviousNode is XElement prevLine && prevLine.Name == "LINEXXXDEF" && prevLine.Elements("ASCMPXXDEF").Any()); // 合并两类结果 var allMatchedNodes = firstCategory.Concat(secondCategory); // 示例:输出匹配节点的lineno属性 foreach (var node in allMatchedNodes) { Console.WriteLine($"匹配节点 lineno: {node.Attribute("lineno")?.Value ?? "无"}"); } } }
2. 传统XmlDocument写法
适合维护旧项目时使用:
using System; using System.Xml; class XmlNodeFilter { static void Main() { XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load("target.xml"); // 用之前的XPath直接筛选两类节点 XmlNodeList matchedNodes = xmlDoc.SelectNodes("//LINEXXXDEF[ASCMPXXDEF] | //LINEXXXDEF[EXDSCXXDEF][preceding-sibling::LINEXXXDEF[1][ASCMPXXDEF]]"); // 示例:遍历输出结果 Console.WriteLine("匹配的节点:"); foreach (XmlNode node in matchedNodes) { XmlAttribute linenoAttr = node.Attributes["lineno"]; Console.WriteLine($"lineno: {linenoAttr?.Value ?? "无"}"); } } }
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

