2009-12-16 96 views
2

我正在嘗試學習XSLT(適用於某些節日編碼的樂趣)。我想我現在對基礎知識有很好的理解(抓取子樹,濾除元素和重命名元素)。我在遇到麻煩的時候就是大幅度重組XML結構。如果你有一個深層嵌套的結構並想扁平它,你會如何去做呢?在XSLT中展平深度嵌套結構

例如,假設我試圖改變一個DocBook片段轉換爲HTML ...

輸入(docbook的):

<section> 
    <title>Title A</title> 
    <para>foo</para> 
    <para>bar</para> 
    <section> 
    <title>Title B</title> 
    <para>baz</para> 
    <para>biz</para> 
    <section> 
     <title>Title C</title> 
     <para>bing</para> 
    </section> 
    </section> 
    <section> 
    <title>Title D</title> 
    <para>fizzle</para> 
    </section> 
</section> 

輸出(HTML):

<h1>Title A</h1> 
<p>foo</p> 
<p>bar</p> 
<h2>Title B</h2> 
<p>baz</p> 
<p>biz</p> 
<h3>Title C</h3> 
<p>bing</p> 
<h2>Title D</h2> 
<p>fizzle</p> 

這是xsl:paramxsl:call-template發揮作用嗎?

謝謝!

+0

看到[這個問題](http://stackoverflow.com/questions/1900184/how-to-break-the-tree-structure-of-the-xml-document-to-desired-one) –

回答

6

卡斯滕的測試案例作品(含有少量的調整,需要終止xsl:value-of用/),但始終使用<h2>作爲標題。如果您想根據標題的嵌套級別使用不同的標題elemenents,那麼你就需要另外的東西吧:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 

    <xsl:template match="/"> 
    <html> 
     <body> 
     <xsl:apply-templates /> 
     </body> 
    </html> 
    </xsl:template> 

    <xsl:template match="title"> 
    <xsl:choose> 
     <xsl:when test="count(ancestor::section) = 1"> 
     <h1><xsl:value-of select="." /></h1> 
     </xsl:when> 
     <xsl:when test="count(ancestor::section) = 2"> 
     <h2><xsl:value-of select="." /></h2> 
     </xsl:when> 
     <xsl:otherwise> 
     <h3><xsl:value-of select="." /></h3> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:template> 

    <xsl:template match="para"> 
    <p><xsl:value-of select="." /></p> 
    </xsl:template> 

</xsl:stylesheet> 

的XPath函數count(ancestor::section)將返回所有<section>元素是父母的計數當前元素。在這個例子中,我使用了<h1><h2>作爲兩個最外層的層次,而<h3>作了更深層的嵌套,但是當然你可以在你的冒犯中使用其他的區分。

這將甚至有可能產生上飛的標題後的數目,使用此表達式:

<xsl:template match="title"> 
    <xsl:variable name="heading">h<xsl:value-of select="count(ancestor::section)" /></xsl:variable> 
    <xsl:element name="{$heading}"> 
     <xsl:value-of select="." /> 
    </xsl:element> 
    </xsl:template> 

在那裏xsl:variable部分創建與h +嵌套級的值的變量。然後該變量可用作xsl:element元素的參數,該參數允許您動態定義要創建的元素的名稱。

跟帖:如果你想只使用H1-H6的建議,你可以做這樣的:

<xsl:template match="title"> 
    <xsl:variable name="hierarchy" select="count(ancestor::section)"/> 
    <xsl:variable name="heading">h<xsl:value-of select="$hierarchy" /></xsl:variable> 

    <xsl:choose> 
    <xsl:when test="$hierarchy > 6"> 
     <h6 class="{$heading}"><xsl:value-of select="." /></h6> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:element name="{$heading}"> 
     <xsl:value-of select="." /> 
     </xsl:element> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

該表達式使用<h6 class="h...">對於任何有嵌套深度大於6,對於所有其他層級使用<h1><h6>

+0

太棒了!感謝全面的教訓! – splicer

+0

不錯的工作。 :)我會爲第二個模板的count(ancestor :: section)<7'添加一個檢查以防止創建''元素。 – Tomalak

1

本應該做的工作:

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0"> 

    <xsl:template match="/"> 
      <html><header> 
       <xsl:apply-templates/> 
      </header></html> 
    </xsl:template> 

    <xsl:template match="title"> 
     <h2><xsl:value-of select="." /></h2> 
    </xsl:template> 

    <xsl:template match="para"> 
     <p><xsl:value-of select="." /></p> 
    </xsl:template> 
    </xsl:stylesheet> 

壓扁你不需要調用模板。 如果使用call-template你交出一些attribs,看here