XSLT 函数获取节点的 xpath

roh*_*hit 3 xslt xpath xmlnode

我需要一个 XSLT 函数,它将返回到它调用的节点的 xpath。

XML

    <root>
      <node>
        <subnode />
        <subnode />
        <subnode />
      </node>
      <node>
        <subnode>
          <subsubnode >
            <xsl:value-of select="fn:generateXPath()" />
          </subsubnode >
        </subnode>
      </node>
    </root>
Run Code Online (Sandbox Code Playgroud)

XSL

    <xsl:template match="root/node/subnode/sub" >
        <xsl:value-of select="fn:generateXPath()" />
    </xsl:template>

    <xsl:function name="fn:generateXPath" >
      <xsl:for-each select="ancestor::*">
      <xsl:value-of select="name()" />
      </xsl:for-each>
      <xsl:value-of select="name()" /> 
    </xsl:function>
Run Code Online (Sandbox Code Playgroud)

我尝试了上面的函数,但它抛出了一个错误:

XPDY0002:无法在此处选择节点:上下文项未定义

但是当我在命名模板中尝试这个时,我能够得到结果。这可以使用xslt:function.

Dim*_*hev 6

我尝试了上面的函数,但它抛出了一个错误:

XPDY0002: Cannot select a node here: the context item is undefined
Run Code Online (Sandbox Code Playgroud)

但是当我在命名模板中尝试这个时,我能够得到结果。

根据 W3C XSLT 2.0 规范:

在样式表函数的主体内,焦点最初是未定义的;这意味着任何试图引用上下文项、上下文位置或上下文大小的尝试都是不可恢复的动态错误。[XPDY0002]”

在您的代码中:

<xsl:function name="fn:generateXPath" >    
  <xsl:for-each select="ancestor::*">    
  <xsl:value-of select="name()" />    
  </xsl:for-each>    
  <xsl:value-of select="name()" />     
</xsl:function>    
Run Code Online (Sandbox Code Playgroud)

有许多相对表达式只能针对上下文项(焦点、当前节点)进行评估,但是没有这样的定义(请参阅上面的引用),因此您会收到报告的错误。

解决方案

为这个函数添加一个参数——很自然,这将是节点,用于选择所需的 XPath:

<xsl:function name="fn:generateXPath" as="xs:string" >
  <xsl:param name="pNode" as="node()"/>

  <xsl:for-each select="$pNode/ancestor::*">    
    <xsl:value-of select="name()" />    
  </xsl:for-each>    
  <xsl:value-of select="name($pNode)" />     
</xsl:function>    
Run Code Online (Sandbox Code Playgroud)

并按以下方式调用此函数:

fn:generateXPath(someNode)
Run Code Online (Sandbox Code Playgroud)

注意:显然,您必须将每个名称连接到一个"/"字符,并通过使用谓词中的位置来缩小表达式的范围,不要选择节点的任何兄弟节点。有关为节点构建 XPath 表达式的完整且正确的解决方案,请参阅我对此问题的回答:https : //stackoverflow.com/a/4747858/36305


Mic*_*Kay 6

没有标准函数的原因之一是人们出于不同的原因想要路径:

有时a/b/c/d就够了。

有些人想要a[3]/b[5]/c[1]/d[2]

有些人想要一个名称不包含名称空间前缀的路径,所以它必须是这样的

*:a[namespace-uri()='abc']/*:b[namespace-uri='xyz'] 等等。