2009-04-20 57 views
3

我該如何使用這個xml,併爲每個「section」元素創建一個具有列的表格,然後使用xslt顯示該列中的所有「document」元素?xslt:我如何使用xslt創建一個包含多個列和行的表?

<Documents> 
    <Section> 
    <SectionName>Green</SectionName> 
    <Document> 
     <FileName>Tier 1 Schedules</FileName>  
    </Document> 
    <Document> 
     <FileName>Tier 3 Schedules</FileName>  
    </Document> 
    <Document> 
     <FileName>Setback Schedule</FileName>  
    </Document> 
    <Document> 
     <FileName>Tier 2 Governance</FileName>  
    </Document> 
</Section> 
<Section> 
<SectionName>MRO/Refurb</SectionName> 
    <Document> 
    <FileName>Tier 2 Governance</FileName>  
    </Document> 
</Section> 

感謝, 鋁

+0

表?柱?它們不是標準的XML單詞。你在翻譯什麼? XHTML? – bortzmeyer 2009-04-20 15:17:42

+0

@bortzmeyer:我認爲一個(X)的HTML表格就是OP之後的東西。 – Tomalak 2009-04-20 16:01:58

+0

我想你不應該接受我的答案。我相信,如果你把問題留在這裏,更好的選擇就會顯現出來。 – Tomalak 2009-04-20 16:05:53

回答

1

這是一個可能的解決方案:

<xsl:variable name="vCountRows"> 
    <xsl:apply-templates select="Documents/Section[1]" mode="findmax" /> 
</xsl:variable> 

<xsl:variable name="vCountCols" select="count(Documents/Section)" /> 

<xsl:template match="/Documents"> 
    <table r="{$vCountRows}" s="{$vCountCols}"> 
    <thead> 
     <xsl:call-template name="create-thead" /> 
    </thead> 
    <tbody> 
     <xsl:call-template name="create-tr" /> 
    </tbody> 
    </table> 
</xsl:template> 

<xsl:template name="create-thead"> 
    <tr> 
    <xsl:apply-templates select="Section" /> 
    </tr>  
</xsl:template> 

<xsl:template match="Section"> 
    <th><xsl:value-of select="SectionName" /></th> 
</xsl:template> 

<xsl:template name="create-tr"> 
    <xsl:param name="row" select="1" /> 

    <tr> 
    <xsl:call-template name="create-td"> 
     <xsl:with-param name="row" select="$row" /> 
    </xsl:call-template> 
    </tr> 

    <xsl:if test="$row &lt; $vCountRows"> 
    <xsl:call-template name="create-tr"> 
     <xsl:with-param name="row" select="$row + 1" /> 
    </xsl:call-template> 
    </xsl:if> 

</xsl:template> 

<xsl:template name="create-td"> 
    <xsl:param name="col" select="1" /> 
    <xsl:param name="row" select="1" /> 

    <td> 
    <xsl:value-of select="Section[$col]/Document[$row]/FileName" /> 
    </td> 

    <xsl:if test="$col &lt; $vCountCols"> 
    <xsl:call-template name="create-td"> 
     <xsl:with-param name="col" select="$col + 1" /> 
     <xsl:with-param name="row" select="$row" /> 
    </xsl:call-template> 
    </xsl:if> 
</xsl:template> 

<xsl:template match="Section" mode="findmax"> 
    <xsl:variable name="c" select="count(Document)" /> 
    <xsl:variable name="next" select="following-sibling::Section[count(Document) &gt; $c][1]" /> 

    <xsl:choose>  
    <xsl:when test="$next"> 
     <xsl:apply-templates select="$next" mode="findmax" /> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:value-of select="$c" /> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

與您輸入它產生:

<table> 
    <thead> 
    <tr> 
     <td>Green</td> 
     <td>MRO/Refurb</td> 
    </tr> 
    </thead> 
    <tbody> 
    <tr> 
     <td>Tier 1 Schedules</td> 
     <td>Tier 2 Governance</td> 
    </tr> 
    <tr> 
     <td>Tier 3 Schedules</td> 
     <td></td> 
    </tr> 
    <tr> 
     <td>Setback Schedule</td> 
     <td></td> 
    </tr> 
    <tr> 
     <td>Tier 2 Governance</td> 
     <td></td> 
    </tr> 
    </tbody> 
</table> 

的一般pporach是這樣的:

  1. 瞭解我們有多少行會得到(這種情況發生在<xsl:template match="Section" mode="findmax">,其中遞歸發現部分與<Document>節點的最大數量
  2. 瞭解我們有多少列去得到(通過計算<Section> S上的號碼)
  3. 呼籲創建一個<tr>一個模板,並保持自稱,直到所有必要的行,已經創造了這個模板
  4. ,第二個模板被調用時,這個創建<td> s。直到它到達列的最大數量(步驟2)它保持自稱

算法:

  • 採用遞增欄柱和行號爲指標
  • 使用遞歸來實現一個(因爲在XSLT中實際上增加變量是不可能的)
  • 爲文檔較少的節創建適當數量的空單元格

存在更高效的版本(可能使用<xsl:key>),我會考慮進一步優化我的版本。

3

該解決方案不使用遞歸,並使用一些有用的XSLT技術,如Muenchian分組,鍵,找到最大值並迭代而不遞歸。

該轉化

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 

    <xsl:strip-space elements="*"/> 

    <xsl:key name="kSectsByValue" match="SectionName" 
     use="."/> 

    <xsl:key name="kDocBySect" match="Document" 
     use="../SectionName"/> 

    <xsl:variable name="vCols" select= 
     "/*/*/SectionName 
       [generate-id() 
       =   
       generate-id(key('kSectsByValue',.)[1]) 
       ]"/> 

    <xsl:variable name="vMaxRows"> 
      <xsl:for-each select="$vCols"> 
       <xsl:sort data-type="number" order="descending" 
        select="count(key('kDocBySect', .))"  /> 
       <xsl:if test="position() = 1"> 
       <xsl:value-of select="count(key('kDocBySect', .))"/> 
       </xsl:if> 
      </xsl:for-each> 
    </xsl:variable> 

    <xsl:template match="/"> 
      <table> 
       <tr> 
       <xsl:apply-templates select="$vCols"/> 
       </tr> 

       <xsl:for-each select= 
       "(/*/*/Document)[not(position() > $vMaxRows)]">     
       <tr> 

        <xsl:variable name="vPos" select="position()"/> 

        <xsl:for-each select="$vCols"> 
        <td> 
         <xsl:value-of select= 
          "../Document[$vPos]/FileName"/> 
        </td> 
        </xsl:for-each> 

       </tr> 
       </xsl:for-each> 
      </table> 

    </xsl:template> 

    <xsl:template match="SectionName"> 
      <td> 
       <xsl:value-of select="." /> 
      </td> 
    </xsl:template> 
</xsl:stylesheet> 

當在原始XML文檔施加(校正爲良好的形成):

<Documents> 
    <Section> 
     <SectionName>Green</SectionName> 
     <Document> 
      <FileName>Tier 1 Schedules</FileName> 
     </Document> 
     <Document> 
      <FileName>Tier 3 Schedules</FileName> 
     </Document> 
     <Document> 
      <FileName>Setback Schedule</FileName> 
     </Document> 
     <Document> 
      <FileName>Tier 2 Governance</FileName> 
     </Document> 
    </Section> 
    <Section> 
     <SectionName>MRO/Refurb</SectionName> 
     <Document> 
      <FileName>Tier 2 Governance</FileName> 
     </Document> 
    </Section> 
</Documents> 

生成所需的結果

<table> 
    <tr> 
     <td>Green</td> 
     <td>MRO/Refurb</td> 
    </tr> 
    <tr> 
     <td>Tier 1 Schedules</td> 
     <td>Tier 2 Governance</td> 
    </tr> 
    <tr> 
     <td>Tier 3 Schedules</td> 
     <td/> 
    </tr> 
    <tr> 
     <td>Setback Schedule</td> 
     <td/> 
    </tr> 
    <tr> 
     <td>Tier 2 Governance</td> 
     <td/> 
    </tr> 
</table> 

請注意

  1. 我們使用Muenchian method for grouping,以便找到各種不同的列名,而不是依靠該XML文檔中他們將是獨一無二的。

  2. Keys使用都爲Muenchian分組和查找屬於一列的所有項目。

  3. 的最大行數被發現並保持在變量$vMaxRows

  4. 我們反覆N次產生表的N行 - 不使用遞歸

  5. N個行通過應用模板到具有其列位置N所有列項輸出。