基于变量的XSL递归遍历

时间:2015-09-21 10:48:05

标签: xslt

我试图了解XSL递归。我需要使用带有单元标记的XSLT基于XML构建HTML表,其中位置映射到名为name的字符串属性,格式为" row.column"。

我尝试以递归方式从最后一个单元格开始并重新计数到第一个单元格(0.0)并开始构建表格。其原因是一些细胞可能跨越几个细胞位置。因此,为了在HTML中使用,我不能只在for-each循环中处理单元格。最后一个单元格由表格属性标识; BodyRowCount和ColumnCount。

XML看起来像这样



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

结果应该是这样的

&#13;
&#13;
<Table>
	<tr> 
		<td>1</td> 	<td>5</td> 
	</tr>
	<tr> 
		<td> colspan="2">2</td>
	</tr>
	<tr> 
		<td>3</td> <td>7</td> 
	</tr>
	<tr> 
		<td>4</td> 	<td>8</td> 
	</tr>
</Table>
&#13;
&#13;
&#13;

以下伪格式的XLS。我试图在这个案例中以名称4.2的Cell传递参数,但是根据属性传递参数似乎是不合理的,但这肯定是可能的吗?

&#13;
&#13;
<xsl:template match="Table"> 	
	<table>
		<xsl:apply-templates select="Cell[@Name = concat(@BodyRowCount,':',ColumnCount)']"/>
	</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.*">
	Call template with 'ROW-1, COLUMN back to max
	<xsl:apply-templates select="Cell[@Name = 'ROW-1:MAXCOLUMN']"> 
	 new row goes here
	 <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='*.*">
	Call template with one column before
	<xsl:apply-templates select="Cell[@Name = SAME ROW:COLUMN-1']"> 
	<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>
&#13;
&#13;
&#13;

我正在寻找关于如何在4.2中启动递归循环的一些帮助回到0.0,通过遍历所有位置来构建表并插入单元格值(如果存在)?

1 个答案:

答案 0 :(得分:0)

你不需要递归。 xslt(1.0)方法可能如下所示:

BenchmarkBitCountFast-4 100000000           19.5 ns/op         0 B/op          0 allocs/op
BenchmarkBitCountOrig-4 20000000            96.1 ns/op        16 B/op          1 allocs/op

怎么做?
- 在行信息上构建一个键(Name属性的第一个字符)
- 为找到的单元格上的行应用模板 - 在变量
中保存Name属性的第一个字符 - 检查是否存在具有相同第一个字符的兄弟姐妹    - 如果没有,添加colspan(不需要XML中的信息,但可以使用)
   - 如果是,请为第二个单元格应用模板

而不是&lt; xsl:value-of select =“。”/&gt;您可以使用&lt; xsl:apply-templates /&gt;。这对于初学者来说并不那么明显,但更直接的xslt。纯粹主义者会要求它。

编辑@Christian:键使用属性“name”的第一个字符,因此它为找到的每个第一个字符返回一个“cell”元素。这是每行一个,因此您可以在xml树中显示这些信息而不显示此信息。如果存在具有相同第一字符的后续单元格,则检测该行中的附加单元格。

编辑@Christian:xslt 2.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>