可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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