2015-09-21 142 views
1

我想讓我的頭繞過XSL遞歸。我需要使用帶有單元標籤的XSLT構建基於XML的HTML表格,其中位置映射到名爲格式爲「row.column」的名稱的字符串屬性。基於變量的XSL遞歸遍歷

我想遞歸地從最後一個單元格開始計數回到第一個單元格(0.0)並開始構建表格。原因是有些單元可能跨越幾個單元位置。因此,爲了在HTML中使用,我不能只在for-each循環中處理單元格。最後一個單元格由表格屬性標識; BodyRowCount和ColumnCount。

的XML看起來像這樣

<Table HeaderRowCount="0" FooterRowCount="0" BodyRowCount="4" ColumnCount="2" > 
 
\t <Cell Self="ucd8iceei0" Name="0:0" RowSpan="1" ColumnSpan="1"> 
 
\t \t <Content>1</Content> 
 
\t </Cell> 
 
\t <Cell Self="ucd8iceei1" Name="1:0" RowSpan="1" ColumnSpan="1"> 
 
\t \t <Content>2</Content> 
 
\t </Cell> 
 
\t <Cell Self="ucd8iceei2" Name="2:0" RowSpan="1" ColumnSpan="2> 
 
\t \t <Content>3</Content> 
 
\t </Cell> 
 
\t <Cell Self="ucd8iceei3" Name="3:0" RowSpan="1" ColumnSpan="1"> 
 
\t \t <Content>4</Content> 
 
\t </Cell> 
 
\t <Cell Self="ucd8iceei4" Name="0:1" RowSpan="1" ColumnSpan="1"> 
 
\t \t <Content>5</Content> 
 
\t </Cell> 
 
\t <Cell Self="ucd8iceei6" Name="2:1" RowSpan="1" ColumnSpan="1"> 
 
\t \t <Content>7</Content> 
 
\t </Cell> 
 
\t <Cell Self="ucd8iceei7" Name="3:1" RowSpan="1" ColumnSpan="1"> 
 
\t \t <Content>8</Content> 
 
\t </Cell> 
 
</Table>

結果應該是這樣的

<Table> 
 
\t <tr> 
 
\t \t <td>1</td> \t <td>5</td> 
 
\t </tr> 
 
\t <tr> 
 
\t \t <td> colspan="2">2</td> 
 
\t </tr> 
 
\t <tr> 
 
\t \t <td>3</td> <td>7</td> 
 
\t </tr> 
 
\t <tr> 
 
\t \t <td>4</td> \t <td>8</td> 
 
\t </tr> 
 
</Table>

僞形式的XLS在下面。我嘗試在名爲4.2的Cell中傳遞參數以開始這種情況,但似乎是不合法的,不能通過基於屬性的參數,但是這肯定是可能的?

<xsl:template match="Table"> \t 
 
\t <table> 
 
\t \t <xsl:apply-templates select="Cell[@Name = concat(@BodyRowCount,':',ColumnCount)']"/> 
 
\t </table> 
 
</xsl:template> 
 

 
<xsl:template name="Cell[@name='0.0"> 
 
Found first cell, start first row in table 
 
<tr><td colspan=<xsl:value-of select=(concat(3&quot,@ColumnSpan,3&quot)) rowspan=<xsl:value-of select=(concat(3&quot,@rowSpan,3&quot))> Row content here </td></tr> 
 
</xsl:template> 
 

 
<xsl:template name="Cell[@name='0.*"> 
 
\t Call template with 'ROW-1, COLUMN back to max 
 
\t <xsl:apply-templates select="Cell[@Name = 'ROW-1:MAXCOLUMN']"> 
 
\t new row goes here 
 
\t <tr><td colspan=<xsl:value-of select=(concat(3&quot,@ColumnSpan,3&quot)) rowspan=<xsl:value-of select=(concat(3&quot,@rowSpan,3&quot))> Row content here </td></tr> 
 
</xsl:template> 
 

 
<xsl:template name="Cell[@name='*.*"> 
 
\t Call template with one column before 
 
\t <xsl:apply-templates select="Cell[@Name = SAME ROW:COLUMN-1']"> 
 
\t <td colspan=<xsl:value-of select=(concat(3&quot,@ColumnSpan,3&quot)) rowspan=<xsl:value-of select=(concat(3&quot,@rowSpan,3&quot))> Row content here </td> 
 
</xsl:template>

我尋找關於如何啓動的遞歸循環中4.2回到0.0,通過遍歷所有的位置,如果一個存在插入單元格的值建表一些幫助?

+1

您在使用XSLT 1.0和XSLT 2.0? –

+0

嗨我使用V2,但如果我更改爲V1,那麼Andreas提供的示例沒有錯誤地工作。所以看起來版本的行爲有所不同。 – Christian

+0

如果您使用XSLT 2.0,那麼您可以使用內置的分組功能。 - 你能解釋一下什麼決定了這個colspan?在你的例子中,每個單元格都有RowSpan和ColumnSpan屬性 - 但是你的輸出具有不同的值。這是爲什麼? –

回答

0

你不需要爲此遞歸。 xslt(1.0)的方式可能如下所示:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:key name="rows" match="Cell" use="substring(@Name,1,1)"/> 
    <xsl:template match="Table"> 
     <table border="1"> 
      <xsl:apply-templates select="Cell[generate-id() = generate-id(key('rows',substring(@Name,1,1)))]" mode="row"> 
       <xsl:sort select="@Name"/> 
      </xsl:apply-templates> 
     </table> 
    </xsl:template> 
    <xsl:template match="Cell" mode="row"> 
     <xsl:variable name="row" select="substring(@Name,1,1)"/> 
     <tr> 
      <td> 
       <xsl:if test="not(following-sibling::Cell[substring(@Name,1,1) = $row])"> 
        <xsl:attribute name="colspan">2</xsl:attribute> 
       </xsl:if> 
       <xsl:value-of select="."/> 
      </td> 
      <xsl:apply-templates select="following-sibling::Cell[substring(@Name,1,1) = $row]" mode="secondcell"/> 
     </tr> 
    </xsl:template> 
    <xsl:template match="Cell" mode="secondcell"> 
     <td> 
      <xsl:value-of select="."/> 
     </td> 
    </xsl:template> 
</xsl:stylesheet> 

它是如何完成的?
- 建立在各行信息的關鍵(Name屬性的第一個字符)
- 對發現的幹細胞應用的模板行
- 保存名稱屬性的第一個字符變量
- 檢查與相同的,如果下面的兄弟姐妹第一個字符存在
- 如果不加合併單元格(不需要從XML信息,但也可使用)
- 如果是這樣,第二個單元格應用模板

相反<的xsl:value-of的選擇=」 。「/>你可以使用< xsl:apply-templates />。這對於初學者來說不是那麼明顯,但更直接的xslt。純粹主義者會要求它。

編輯@Christian:該鍵使用屬性「name」的第一個字符,因此它爲找到的每個第一個字符返回一個「單元」元素。這是每行一個,所以你可以找出行,而不需要在xml樹中顯式地顯示這些信息。如果以下單元格具有相同的第一個字符,則會檢測該行中的其他單元格。

編輯@Christian:在XSLT 2.0解決方案是越來越短,不需要一個關鍵:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions"> 
    <xsl:template match="Table"> 
     <table border="1"> 
      <xsl:for-each-group select="Cell" group-by="substring(@Name,1,1)"> 
       <tr> 
        <xsl:for-each select="current-group()"> 
         <td> 
          <xsl:if test="count(current-group())=1"> 
           <xsl:attribute name="colspan">2</xsl:attribute> 
          </xsl:if> 
          <xsl:value-of select="."/> 
         </td> 
        </xsl:for-each> 
       </tr> 
      </xsl:for-each-group> 
     </table> 
    </xsl:template> 
</xsl:stylesheet> 
+0

嗨,謝謝。這是完全不同的方法。我必須閱讀'關鍵'表達。但現在看來,它似乎預計行:只允許返回最大一個鍵,並且返回2或更多,因爲更多單元以相同的rownumber開頭? – Christian

+0

@Christian:我添加了一個無鑰匙的xslt 2.0解決方案 – Andreas

+0

這看起來不正確。你認爲有兩列;這可能會改變。此外,'substring(@ Name,1,1)'假定少於10行 - 這也可能改變。 –