2013-07-23 33 views
1

打印XML樹我有下面的XML使用XSL

<?xml version="1.0" encoding="ISO-8859-1"?> 
<?xml-stylesheet type='text/xsl' href='parser.xsl'?> 
<NVS> 
    <A> 
     <F>007</F> 
    </A> 
    <A>-002</A> 
    <B>--003</B> 
    <C> 
     <D>------005</D> 
    </C> 
    <E>-006</E> 
</NVS> 

而且我想打印一樹的每個節點,如:

/NVS/A/ 
/NVS/A/F/ 
/NVS/A/ 
/NVS/B/ 
/NVS/C/ 
/NVS/C/D 
/NVS/E/ 

我嘗試了一些XSL,但我無法承受正確的結果。 最好的XSL是:

<?xml version="1.0" encoding="ISO-8859-1"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="html" encoding="ISO-8859-1" doctype-public="-//W3C//DTD XHTML//EN" doctype-system="http://www.w3.org/TR/2001/REC-xhtml11-20010531" indent="yes"/> 
    <xsl:template match="/*"> 
     <html> 
      <body> 
       <xsl:for-each select=".">/<xsl:value-of select="."/> 
        <br/> 
       </xsl:for-each> 
      </body> 
     </html> 
    </xsl:template> 
</xsl:stylesheet> 

而且我也嘗試了 「每個」,如:

<?xml version="1.0" encoding="ISO-8859-1"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="html" encoding="ISO-8859-1" doctype-public="-//W3C//DTD XHTML//EN" doctype-system="http://www.w3.org/TR/2001/REC-xhtml11-20010531" indent="yes"/> 
    <xsl:template match="/*/*"> 
     <xsl:for-each select=".">/<xsl:value-of select="."/> 
     </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

但不是更好。而且我只是打價值,而我只想要節點的名稱。

任何想法?

回答

1

另一種選擇是使用ancestor-or-self軸返回樹狀結構。

XML輸入

<NVS> 
    <A> 
     <F>007</F> 
    </A> 
    <A>-002</A> 
    <B>--003</B> 
    <C> 
     <D>------005</D> 
    </C> 
    <E>-006</E> 
</NVS> 

XSLT 1。0

<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="text()"/> 

    <xsl:template match="*"> 
     <xsl:for-each select="ancestor-or-self::*"> 
      <xsl:value-of select="concat('/',local-name())"/> 
     </xsl:for-each> 
     <xsl:text>&#xA;</xsl:text> 
     <xsl:apply-templates select="node()"/> 
    </xsl:template> 

</xsl:stylesheet> 

輸出

/NVS 
/NVS/A 
/NVS/A/F 
/NVS/A 
/NVS/B 
/NVS/C 
/NVS/C/D 
/NVS/E 

也可以很容易地修改它以當元素存在不止一次在給定的水平添加謂詞中的位置,得到的準確路徑。例如,/NVS的子項有兩個A元素。

XSLT 1.0

<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="text()"/> 

    <xsl:template match="*"> 
     <xsl:for-each select="ancestor-or-self::*"> 
      <xsl:value-of select="concat('/',local-name())"/> 
      <xsl:if test="(preceding-sibling::*|following-sibling::*)[local-name()=local-name(current())]"> 
       <xsl:value-of select="concat('[',count(preceding-sibling::*[local-name()=local-name(current())])+1,']')"/> 
      </xsl:if> 
     </xsl:for-each> 
     <xsl:text>&#xA;</xsl:text> 
     <xsl:apply-templates select="node()"/> 
    </xsl:template> 

</xsl:stylesheet> 

輸出(使用與上述相同的輸入)

/NVS 
/NVS/A[1] 
/NVS/A[1]/F 
/NVS/A[2] 
/NVS/B 
/NVS/C 
/NVS/C/D 
/NVS/E 

另外,如果你不希望的路徑的根元素輸出,只需添加此模板:

<xsl:template match="/*"> 
    <xsl:apply-templates/> 
</xsl:template> 
+0

處理屬性也很容易。讓我知道你是否想要一個例子。 –

+0

是的!太棒了,它的效果非常好。這正是我所期望的:簡單,輕便和高效。 幾次使用某個元素時,我不需要顯示位置,但看看它是如何完成的很有趣。 順便說一下,' '的需求是什麼? – OranginaRouge

+0

@OranginaRouge - ' '是一個換行符。沒有它,所有的輸出將在一條線上。 –

2

一個可能的解決方案是遍歷樹並隨時跟蹤相應的輸出。例如,當這個XSLT:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:template match="/*"> 
    <xsl:apply-templates mode="children"> 
     <xsl:with-param name="pName" select="name()"/> 
    </xsl:apply-templates> 
    </xsl:template> 

    <xsl:template match="*[*]" mode="children"> 
    <xsl:param name="pName"/> 
    <xsl:variable name="vNewName" select="concat($pName, '/', name())"/> 
    <xsl:value-of select="concat('/', $vNewName, '/&#10;')"/> 
    <xsl:apply-templates mode="children"> 
     <xsl:with-param name="pName" select="$vNewName"/> 
    </xsl:apply-templates> 
    </xsl:template> 

    <xsl:template match="*[not(*)]" mode="children"> 
    <xsl:param name="pName"/> 
    <xsl:value-of select="concat('/', $pName, '/', name(), '/&#10;')"/> 
    </xsl:template> 

</xsl:stylesheet> 

...適用於所提供的XML:

<NVS> 
    <A> 
    <F>007</F> 
    </A> 
    <A>-002</A> 
    <B>--003</B> 
    <C> 
    <D>------005</D> 
    </C> 
    <E>-006</E> 
</NVS> 

...想要的結果產生:

/NVS/A/ 
/NVS/A/F/ 
/NVS/A/ 
/NVS/B/ 
/NVS/C/ 
/NVS/C/D/ 
/NVS/E/ 

說明:

  • Tem板#1匹配根節點並指示處理器將模板應用於其所有子節點,而單獨傳遞參數,該參數目前包含根節點的名稱。請注意使用mode="children";我使用這種方式,以便將來使用更一般匹配的模板不包含此根節點。
  • 模板#2匹配所有有子項的節點(並使用mode="children")。在找到這樣一個節點時,處理器輸出一行文本,該文本結合攜帶的參數,正斜槓和當前元素的名稱。最後,該模板通過將模板應用於所有子節點並傳遞一個參數來模仿模板#1,但是這次該參數包含直到幷包括此節點的連接文本
  • 模板#3匹配沒有孩子的所有節點(並且再次使用mode="children")。在找到這樣一個節點時,處理器輸出一行文本,它與Template#2的功能非常相似。
+0

感謝您的支持快速和清晰的答案。你的解釋對我很有幫助,因爲最後它比我想象的要困難得多。 這也是我爲什麼選擇第二個,以及上面的一個更簡單的解決方案的原因之一。 – OranginaRouge