我的源XML逐列提供数据;细胞的高度不同。使用XSLT 1.0,我需要调整它以匹配HTML的逐行表格式。
示例:我需要像这样转换输入数据
<source>
<column>
<cell height="1">col A row 1</cell>
<cell height="2">col A rows 2-3</cell>
</column>
<column>
<cell height="1">col B row 1</cell>
<cell height="1">col B row 2</cell>
<cell height="1">col B row 3</cell>
</column>
<column>
<cell height="3">col C rows 1-3</cell>
</column>
</source>
进入像这样的HTML表
<table>
<tr>
<td rowspan="1">col A row 1</td>
<td rowspan="1">col B row 1</td>
<td rowspan="3">col C rows 1-3</td>
</tr>
<tr>
<td rowspan="2">col A rows 2-3</td>
<td rowspan="1">col B row 2</td>
</tr>
<tr>
<td rowspan="1">col B row 3</td>
</tr>
</table>
如何?
编辑:这是另一个示例,其中没有单个列的单元格数与表格行数相同。
<source>
<column id="A">
<cell height="1">col A row 1</cell>
<cell height="2">col A rows 2-3</cell>
</column>
<column id="B">
<cell height="2">col B row 1-2</cell>
<cell height="1">col B row 3</cell>
</column>
<column id="C">
<cell height="3">col C rows 1-3</cell>
</column>
</source>
进入像这样的HTML表
<table>
<tr>
<td rowspan="1">col A row 1</td>
<td rowspan="2">col B row 1-2</td>
<td rowspan="3">col C rows 1-3</td>
</tr>
<tr>
<td rowspan="2">col A rows 2-3</td>
</tr>
<tr>
<td rowspan="1">col B row 3</td>
</tr>
</table>
答案 0 :(得分:5)
<强>予。 XSLT 1.0解决方案
此转化:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vrtfPass1">
<xsl:apply-templates mode="pass1"/>
</xsl:variable>
<xsl:variable name="vPass1"
select="ext:node-set($vrtfPass1)"/>
<xsl:variable name="vMaxRow">
<xsl:for-each select=
"$vPass1/*/*/cell/@startRow">
<xsl:sort select="." data-type="number" order="descending"/>
<xsl:if test="position() = 1">
<xsl:value-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:template match="node()|@*" mode="pass1">
<xsl:copy>
<xsl:apply-templates select="node()|@*" mode="pass1"/>
</xsl:copy>
</xsl:template>
<xsl:template match="cell" mode="pass1">
<cell height="{@height}"
startRow="{sum(preceding-sibling::*/@height) +1}">
<xsl:copy-of select="text()"/>
</cell>
</xsl:template>
<xsl:template match="/">
<table>
<xsl:call-template name="makeRows">
<xsl:with-param name="pmaxRow" select="$vMaxRow"/>
</xsl:call-template>
</table>
</xsl:template>
<xsl:template name="makeRows">
<xsl:param name="prowNum" select="1"/>
<xsl:param name="pmaxRow" select="1"/>
<xsl:if test="not($prowNum > $pmaxRow)">
<tr>
<xsl:apply-templates select=
"$vPass1/*/*/cell[@startRow = $prowNum]"/>
</tr>
<xsl:call-template name="makeRows">
<xsl:with-param name="prowNum" select="$prowNum+1"/>
<xsl:with-param name="pmaxRow" select="$pmaxRow"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="cell">
<td rowspan="{@height}"><xsl:value-of select="."/></td>
</xsl:template>
</xsl:stylesheet>
应用于提供的XML文档:
<source>
<column>
<cell height="1">col A row 1</cell>
<cell height="2">col A rows 2-3</cell>
</column>
<column>
<cell height="2">col B row 1-2</cell>
<cell height="1">col B row 3</cell>
</column>
<column>
<cell height="3">col C rows 1-3</cell>
</column>
</source>
生成想要的正确结果:
<table>
<tr>
<td rowspan="1">col A row 1</td>
<td rowspan="2">col B row 1-2</td>
<td rowspan="3">col C rows 1-3</td>
</tr>
<tr>
<td rowspan="2">col A rows 2-3</td>
</tr>
<tr>
<td rowspan="1">col B row 3</td>
</tr>
</table>
<强> II。 XSLT 2.0解决方案:
这类似于XSLT 1.0解决方案,但我们使用max()
函数,并且通过使用to
运算符来避免递归。
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vPass1">
<xsl:apply-templates mode="pass1"/>
</xsl:variable>
<xsl:variable name="vMaxRow" as="xs:integer"
select="max($vPass1/*/*/cell/@startRow/xs:integer(.))"/>
<xsl:template match="node()|@*" mode="pass1">
<xsl:copy>
<xsl:apply-templates select="node()|@*" mode="pass1"/>
</xsl:copy>
</xsl:template>
<xsl:template match="cell" mode="pass1">
<cell height="{@height}"
startRow="{sum(preceding-sibling::*/@height) +1}">
<xsl:copy-of select="text()"/>
</cell>
</xsl:template>
<xsl:template match="/">
<table>
<xsl:for-each select="1 to $vMaxRow">
<tr>
<xsl:apply-templates select=
"$vPass1/*/*/cell[@startRow = current()]"/>
</tr>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template match="cell">
<td rowspan="{@height}"><xsl:value-of select="."/></td>
</xsl:template>
</xsl:stylesheet>