问题
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.
回答1:
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
回答2:
Here's a stylesheet (of dubious value) that prints the path to every element and attribute in a 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, '
')" />
<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(), '
')" />
</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>
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
来源:https://stackoverflow.com/questions/5695964/output-context-node-full-path-in-xslt-1-0