Get current nodes xpath

2019-02-15 08:00发布

问题:

I need to get the xpath of current node for which i have written an xsl function

<func:function name="fn:getXpath">
    <xsl:variable name="xpath">
        <xsl:for-each select="ancestor-or-self::*">
            <xsl:value-of select="concat($xpath, name())" />
            <xsl:if test="not(position()=last())">
                <xsl:value-of select="concat('/', $xpath)" />
            </xsl:if>
        </xsl:for-each>
    </xsl:variable>
    <func:result select="$xpath" />
</func:function>

But when I run this, I'm getting the following error

file:///D:/test.xsl; Line #165; Column #63; Variable accessed before it is bound!
file:///D:/test.xsl; Line #165; Column #63; java.lang.NullPointerException

I'm using xalan 2.7.0. Please help.

回答1:

You are using the variable $xpath inside the definition of the variable itself:

<func:function name="fn:getXpath">
    <xsl:variable name="xpath">  
        <xsl:for-each select="ancestor-or-self::*">
            <xsl:value-of select="concat($xpath, name())" />   <-------
            <xsl:if test="not(position()=last())">
                <xsl:value-of select="concat('/', $xpath)" />  <-------
            </xsl:if>
        </xsl:for-each>
    </xsl:variable>
    <func:result select="$xpath" />
</func:function>

The variable is not known at that point.



回答2:

In your example you are trying to use the variable in the definition itself, which is not valid.

It looks your intention is to try and modify the value of an existing value. However XSLT is a functional language, and as a result variables are immutable. This means you cannot change the value once defined.

In this case, you don't need to be so complicated. You can just remove the reference to the variable itself, and you will get the result you need

<func:function name="fn:getXpath">
   <xsl:variable name="xpath">
      <xsl:for-each select="ancestor-or-self::*">
         <xsl:value-of select="name()"/>
         <xsl:if test="not(position()=last())">
            <xsl:value-of select="'/'"/>
         </xsl:if>
      </xsl:for-each>
   </xsl:variable>
   <func:result select="$xpath" />
</func:function>