.NET/C#环境下如何实现XPath跨文档自动跳转取值?
可行解决方案
前置说明
.NET 原生System.Xml类库默认仅支持XPath 1.0/XSLT 1.0,若要使用XSLT 3.0能力,引入Saxon开源版.NET库即可适配.NET Core环境的标准支持。
方案1:XSLT 3.0 自定义函数实现
如果可以接受在XPath中添加自定义函数调用,可直接通过XSLT 3.0标准能力实现跳转逻辑,代码示例如下:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:local="urn:local-functions"> <!-- 自定义自动跳转解析函数 --> <xsl:function name="local:auto-follow" as="node()?"> <xsl:param name="current-node" as="node()"/> <xsl:choose> <!-- 匹配#开头的ID格式节点值 --> <xsl:when test="matches($current-node/text(), '^#\d+$')"> <!-- 提取ID拼接地址加载目标文档 --> <xsl:variable name="doc-id" select="substring($current-node/text(), 2)"/> <xsl:sequence select="doc(concat('http://example.com/', $doc-id))"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="$current-node"/> </xsl:otherwise> </xsl:choose> </xsl:function> <!-- 调用示例 --> <xsl:value-of select="local:auto-follow(aa/bb)/cc/dd"/> </xsl:stylesheet>
运行后输出结果即为Hello。
方案2:自定义XPathNavigator实现原生路径支持
如果需要完全兼容aa/bb/cc/dd的原生XPath写法,无需额外函数调用,可通过继承XPathNavigator重写节点遍历逻辑实现,核心C#代码如下:
using System.Xml.XPath; using System.Text.RegularExpressions; public class AutoFollowXPathNavigator : XPathNavigator { private XPathNavigator _innerNavigator; public AutoFollowXPathNavigator(XPathNavigator root) { _innerNavigator = root.Clone(); } // 重写核心节点选择方法,注入跳转逻辑 public override XPathNodeIterator SelectChildren(string name, string namespaceURI) { // 检测当前节点是否为跳转格式 if (_innerNavigator.NodeType == XPathNodeType.Element && Regex.IsMatch(_innerNavigator.Value, @"^#\d+$")) { // 加载目标文档并切换上下文 var docId = _innerNavigator.Value.TrimStart('#'); var targetDoc = new XPathDocument($"http://example.com/{docId}"); _innerNavigator = targetDoc.CreateNavigator(); } return _innerNavigator.SelectChildren(name, namespaceURI); } // 其余XPathNavigator抽象方法按相同逻辑重写_innerNavigator对应的方法即可 // 剩余方法实现仅需透传_innerNavigator的对应调用,此处省略重复代码 }
使用时代码无需修改原有XPath表达式:
XPathDocument document = new XPathDocument("http://example.com/#1111"); XPathNavigator navigator = new AutoFollowXPathNavigator(document.CreateNavigator()); string result = navigator.Evaluate("aa/bb/cc/dd").ToString(); // result输出为Hello
内容的提问来源于stack exchange,提问作者docjosh
相关产品推荐
相关产品推荐

