如何用XPath选择XML中两个指定CHAPTER节点间的所有节点?
解决方案:用XPath轴选择两个节点之间的所有内容
你提到的.NET里确实没有直接的SelectAllNodesBetween方法,但我们可以通过XPath的**轴(Axes)**特性来实现这个需求,不需要额外编写自定义方法。下面根据你的XML结构,分两种常见场景给出具体方案:
场景1:选择两个CHAPTER节点之间的所有节点(含自身及子节点)
如果你的目标是获取CHAPTER[@cnumber='1']到CHAPTER[@cnumber='3']之间的全部内容(包括这两个CHAPTER节点,以及中间的CHAPTER 2),可以用两种XPath写法:
简洁数字范围写法(适用于cnumber为纯数字字符串的场景)
/XMLBIBLE/BIBLEBOOK[@bname='1 Mose']/CHAPTER[ @cnumber='1' or (@cnumber > '1' and @cnumber < '3') or @cnumber='3' ]
基于兄弟节点轴的通用写法(不受数字格式限制)
/XMLBIBLE/BIBLEBOOK[@bname='1 Mose']/CHAPTER[@cnumber='1'] | /XMLBIBLE/BIBLEBOOK[@bname='1 Mose']/CHAPTER[@cnumber='1']/following-sibling::CHAPTER[preceding-sibling::CHAPTER[@cnumber='1'] and following-sibling::CHAPTER[@cnumber='3']] | /XMLBIBLE/BIBLEBOOK[@bname='1 Mose']/CHAPTER[@cnumber='3']
场景2:选择两个VERS节点之间的所有节点(跨CHAPTER内容)
如果需要精确从CHAPTER 1下的VERS[@vnumber='1'],到CHAPTER 3下的VERS[@vnumber='1']之间的所有节点(包括这两个VERS、中间的CHAPTER 2及其子节点),可以用组合式XPath:
<!-- 起始VERS节点 --> /XMLBIBLE/BIBLEBOOK[@bname='1 Mose']/CHAPTER[@cnumber='1']/VERS[@vnumber='1'] | <!-- 起始CHAPTER的后续兄弟节点(在结束CHAPTER之前)的所有节点(含自身和子节点) --> /XMLBIBLE/BIBLEBOOK[@bname='1 Mose']/CHAPTER[@cnumber='1']/following-sibling::CHAPTER[preceding-sibling::CHAPTER[@cnumber='1'] and following-sibling::CHAPTER[@cnumber='3']]/descendant-or-self::* | <!-- 结束CHAPTER中,结束VERS之前的所有VERS节点 --> /XMLBIBLE/BIBLEBOOK[@bname='1 Mose']/CHAPTER[@cnumber='3']/VERS[@vnumber='1']/preceding-sibling::VERS | <!-- 结束VERS节点 --> /XMLBIBLE/BIBLEBOOK[@bname='1 Mose']/CHAPTER[@cnumber='3']/VERS[@vnumber='1']
整合到你的C#代码中
你可以把这个逻辑和现有代码结合,动态生成XPath:
// 提取动态参数 string targetBook = entry.NumberFrom + " " + entry.NameFrom; string startChapter = entry.ChapterFrom; string startVers = entry.VersFrom; string endChapter = "3"; // 可替换为你的目标章节参数 string endVers = "1"; // 可替换为你的目标经文参数 // 构建完整XPath表达式 string xPath = $@" /XMLBIBLE/BIBLEBOOK[@bname='{targetBook}']/CHAPTER[@cnumber='{startChapter}']/VERS[@vnumber='{startVers}'] | /XMLBIBLE/BIBLEBOOK[@bname='{targetBook}']/CHAPTER[@cnumber='{startChapter}']/following-sibling::CHAPTER[preceding-sibling::CHAPTER[@cnumber='{startChapter}'] and following-sibling::CHAPTER[@cnumber='{endChapter}']]/descendant-or-self::* | /XMLBIBLE/BIBLEBOOK[@bname='{targetBook}']/CHAPTER[@cnumber='{endChapter}']/VERS[@vnumber='{endVers}']/preceding-sibling::VERS | /XMLBIBLE/BIBLEBOOK[@bname='{targetBook}']/CHAPTER[@cnumber='{endChapter}']/VERS[@vnumber='{endVers}'] "; // 执行节点选择 XmlNodeList nodeList = xmlDocument.SelectNodes(xPath);
补充提示
- 如果XML中的
cnumber和vnumber是数字类型(而非字符串),可以去掉属性值的引号,直接用@cnumber=1这类写法。 - 如果只需要选择同级节点(不包含子节点),删除表达式中的
descendant-or-self::*即可。
内容的提问来源于stack exchange,提问作者Fabian
相关产品推荐
相关产品推荐

