2011-04-17 41 views
3

出於調試的目的,從模板中輸出上下文節點的完整路徑會很方便,是否有未縮放的xpath或函數來報告此問題?XSLT 1.0中的輸出上下文節點(完整路徑)?

實施例模板:

<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 

或類似的東西。

+0

[列出XML文件中的每個節點。](http://stackoverflow.com/questions/4051987/list-every-node-in-an-xml-file)或[HTML XPa th - 如何獲取基於另一個元素的值的元素的XPath?](http://stackoverflow.com/questions/5227330/html-xpath-how-to-get-the-xpath-of-an- element-based-on-the-value-of-ele-ele) – 2011-04-17 20:42:08

回答

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

這確實適用於給出的XML示例,謝謝。我現在試圖讓它與我的更復雜的真實例子一起工作,但它似乎並不匹配....我需要仔細觀察並找出原因.... [edit]我看到它,有一個硬編碼ref在@first裏面...讓我改變這一輪,以適應我的實際XML ... – monojohnny 2011-04-18 13:56:00

+0

是的,很好的作品 - 非常感謝你。對於我的實際需求,我需要編輯一下才能更普遍地工作,但這是一個很棒的模板。乾杯! – monojohnny 2011-04-18 14:08:37

+0

正如一邊(我認爲別人也問這個在其他地方的stackoverflow) - 是否有一個通用的'xsl:pwd'或'xsl:name-of'可用,它可以更普遍地注入任何文檔進行調試。 ..我可以想象(可能)這些事情的遞歸性質意味着模板不能「意識到」文檔中的全部深度(而不必向上遍歷),所以我想這就是爲什麼我們沒有一個現成的...... – monojohnny 2011-04-18 14:15:35

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