Node output context (full path) in XSLT 1.0?

For debugging purposes, it would be useful to infer the full path from the node context from within the template, is there an implicit xpath or function to report this?

Template example:

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

Example (abbreviated) input:

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

The output from the template will look something like this:

 people / person / name / @first 

Or something similar.

+3
source share
2 answers

This conversion creates an XPath expression for the desired 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 to the following XML document :

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

required, the correct result is obtained :

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

Here is a stylesheet (of dubious value) that prints the path to each element and attribute in the document:

 <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:param name="pathToHere" select="''" /> <xsl:variable name="precSiblings" select="count(preceding-sibling::*[name()=name(current())])" /> <xsl:variable name="follSiblings" select="count(following-sibling::*[name()=name(current())])" /> <xsl:variable name="fullPath" select="concat($pathToHere, '/', name(), substring(concat('[', $precSiblings + 1, ']'), 1 div ($follSiblings or $precSiblings)))" /> <xsl:value-of select="concat($fullPath, '&#xA;')" /> <xsl:apply-templates select="@*|*"> <xsl:with-param name="pathToHere" select="$fullPath" /> </xsl:apply-templates> </xsl:template> <xsl:template match="@*"> <xsl:param name="pathToHere" select="''" /> <xsl:value-of select="concat($pathToHere, '/@', name(), '&#xA;')" /> </xsl:template> </xsl:stylesheet> 

When applied to this input:

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

It produces:

 /people /people/person[1] /people/person[1]/name /people/person[1]/name/@first /people/person[1]/name/@last /people/person[2] /people/person[2]/name /people/person[2]/name/@first /people/person[2]/name/@last /people/singleElement 
+1
source

All Articles