在XSLT 1.0中如何输出上下文节点的完整路径?

3
为了调试目的,在模板内输出上下文节点的完整路径将非常方便,是否有未缩写的XPath或函数可用于报告此信息?
示例模板:
<xsl:template match="@first">
        <tr>
            <td>
                <xsl:value-of select="??WHAT TO PUT IN HERE??"/>
            </td>
        </tr>
</xsl:template>

示例(简化)输入文档:

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

模板的输出应该是这样的:

输出结果如下:

people / person / name / @first 

或类似的东西。

2个回答

2

这个转换会产生想要节点的XPath表达式:

<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>

当应用于以下 XML 文档时:

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

期望的结果是正确的:

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

这确实适用于给定的示例XML,谢谢。我现在正在尝试将其与我的更复杂的实际示例一起使用,但似乎没有匹配...我需要仔细查看并解决原因... [编辑] 我看到了,那里有一个硬编码的对@first的引用...让我改变一下以适应我的实际XML... - monojohnny
好的,非常感谢,确实很好用。根据我的实际需求,我需要稍微编辑一下,使之更普适,但这是一个很棒的模板。干杯! - monojohnny
仅作为旁注(我想其他人也在stackoverflow的其他地方问过这个问题)-是否有一般的“xsl:pwd”或“xsl:name-of”可用于更普遍地注入任何文档以进行调试,我想知道...我可以想象(也许)这些事物的递归性质意味着模板不会“意识到”文档中的总深度(而无需向上遍历),所以我猜这就是为什么我们没有现成的原因... - monojohnny
@monojohnny:不,没有一个特殊的函数可以返回节点的XPath表达式——可能部分原因是存在多个这样的XPath表达式,并且没有“标准形式”的定义。 - Dimitre Novatchev

1

这里有一个样式表(价值存疑),可以显示文档中每个元素和属性的路径:

<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>

当应用于此输入时:

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

生成:

/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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接