Search code examples
debuggingxsltcontextpath

Output Context Node (full path) in XSLT 1.0?


For debugging purposes it would be handy to output the full path of the context node from within a template, is there unabbreviated xpath or function to report this ?

Example Template:

<xsl:template match="@first">
        <tr>
            <td>
                <xsl:value-of select="??WHAT TO PUT IN HERE??"/>
            </td>
        </tr>
</xsl:template>

Example (Abridged) input document:

<people>
<person>
<name first="alan">
...

The output from the template would be something like:

people / person / name / @first 

Or something similar.


Solution

  • This transformation produces an XPath expression for the wanted node:

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="text"/>
     <xsl:strip-space elements="*"/>
    
        <xsl:template match="/">
            <xsl:variable name="vNode" select=
            "/*/*[2]/*/@first"/>
            <xsl:apply-templates select="$vNode" mode="path"/>
        </xsl:template>
    
        <xsl:template match="*" mode="path">
            <xsl:value-of select="concat('/',name())"/>
            <xsl:variable name="vnumPrecSiblings" select=
            "count(preceding-sibling::*[name()=name(current())])"/>
            <xsl:variable name="vnumFollSiblings" select=
            "count(following-sibling::*[name()=name(current())])"/>
            <xsl:if test="$vnumPrecSiblings or $vnumFollSiblings">
                <xsl:value-of select=
                "concat('[', $vnumPrecSiblings +1, ']')"/>
            </xsl:if>
        </xsl:template>
    
        <xsl:template match="@*" mode="path">
         <xsl:apply-templates select="ancestor::*" mode="path"/>
         <xsl:value-of select="concat('/@', name())"/>
        </xsl:template>
    </xsl:stylesheet>
    

    when applied on the following XML document:

    <people>
     <person>
      <name first="betty" last="jones"/>
     </person>
     <person>
      <name first="alan" last="smith"/>
     </person>
    </people>
    

    the wanted, correct result is produced:

    /people/person[2]/name/@first