获取指向节点的xpath的XSLT函数

4

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

XML

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

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>

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

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

但是当我在一个命名模板中尝试这个函数时,我能够得到结果。是否可以使用 xslt:function 来实现这一点。

2个回答

8
有一个没有标准函数的原因是因为人们需要不同的路径:
有时候 `a/b/c/d` 就足够了。
一些人想要 `a[3]/b[5]/c[1]/d[2]`。
一些人希望路径中的名称不包含命名空间前缀,所以它必须类似于 `*:a[namespace-uri()='abc']/*:b[namespace-uri='xyz']` 等。

8

I tried with the above function but it throws an error:

XPDY0002: Cannot select a node here: the context item is undefined

But when I tried this in a named template I'm able to get the result.

根据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>    

有一些相对表达式只能针对上下文项(焦点、当前节点)进行评估,但是没有通过定义来定义它们(请参见上面的引用),因此您会收到报告的错误。

解决方案

为该函数添加一个参数--自然地,这将是节点,所选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>    

然后以以下方式调用此函数:

fn:generateXPath(someNode)

注意:显然,您需要将每个名称连接到"/"字符,并通过在谓词内使用位置缩小表达式以不选择节点的任何兄弟节点。有关为节点构建XPath表达式的完整和正确解决方案,请参见我对此问题的回答:https://dev59.com/SW445IYBdhLWcg3wq8Lp#4747858


请注意以下有用的缩写 <xsl:value-of select="$pNode/ancestor::*/name()" separator="/"/> - Michael Kay
@MichaelKay:是的,我会这样做。在这里,我只是添加了必要的更改,没有深入研究OP的代码。 - Dimitre Novatchev
我正在将返回值分配给一个变量。我需要从另一个具有相同模式的XML中获取值。为此,我尝试了以下代码:<xsl:variable name="LookUpXml" select="document('sample2.xml')" /> <xsl:value-of select="$LookUpXml/saxon:evaluate($nodePath)" />。但是这会导致错误:XPTY0004:不允许将多个项序列作为saxon:evaluate()的第一个参数。 - rohit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接