我有一个格式如下的XML文件:
<DataSet>
<Data id ="1" columns ="4">
<item name ="data1" value="value1"/>
<item name ="data2" value="value2"/>
<item name ="data3" value="value3"/>
<item name ="data4" value="value4"/>
<item name ="data5" value="value5"/>
</Data>
<Data id="2" columns ="2">
<item name ="data1" value="value1"/>
<item name ="data2" value="value2"/>
<item name ="data3" value="value3"/>
<item name ="data4" value="value4"/>
</Data>
</DataSet>
我需要一个XSL转换来获得以下表结构。这里的想法是在两个相邻的单元格中显示名称和值属性。因此,'item'将与2列相关联,而一行将包含两个项目的名称/值对。列数将在数据元素中指定,并且始终是2的倍数。
<report>
<table>
<tr>
<td>data1</td>
<td>value1</td>
<td>data2</td>
<td>value2</td>
</tr>
<tr>
<td>data3</td>
<td>value3</td>
<td>data4</td>
<td>value4</td>
</tr>
<tr>
<td>data5</td>
<td>value5</td>
<td></td>
<td></td>
</tr>
</table>
<table>
<tr>
<td>data1</td>
<td>value1</td>
</tr>
<tr>
<td>data2</td>
<td>value2</td>
</tr>
<tr>
<td>data3</td>
<td>value3</td>
</tr>
<tr>
<td>data4</td>
<td>value4</td>
</tr>
</table>
</report>
答案 0 :(得分:1)
应用于提供的输入的以下XSL转换会生成所需的输出。下面提供了一些解释。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/DataSet"><report>
<xsl:apply-templates select="@*|node()" />
</report></xsl:template>
<xsl:template match="Data">
<xsl:variable name="count" select="count(item)" />
<xsl:variable name="M" select="@columns div 2" />
<xsl:variable name="N" select="($count + ($count mod $M)) div $M" />
<table>
<xsl:call-template name="nth-row">
<xsl:with-param name="n" select="1" />
<xsl:with-param name="M" select="$M" />
<xsl:with-param name="N" select="$N" />
</xsl:call-template>
</table>
</xsl:template>
<xsl:template name="nth-row">
<xsl:param name="n" />
<xsl:param name="N" />
<xsl:param name="M" />
<tr>
<xsl:call-template name="nmth-cell">
<xsl:with-param name="n" select="$n" />
<xsl:with-param name="m" select="1" />
<xsl:with-param name="N" select="$N" />
<xsl:with-param name="M" select="$M" />
</xsl:call-template>
</tr>
<xsl:if test="$N > $n">
<xsl:call-template name="nth-row">
<xsl:with-param name="n" select="$n + 1" />
<xsl:with-param name="N" select="$N" />
<xsl:with-param name="M" select="$M" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="nmth-cell">
<xsl:param name="n" />
<xsl:param name="m" />
<xsl:param name="N" />
<xsl:param name="M" />
<xsl:variable name="pos" select="($n - 1) * $M + $m" />
<xsl:choose>
<xsl:when test="item[position()=$pos]">
<td><xsl:value-of select="item[position()=$pos]/@name" /></td>
<td><xsl:value-of select="item[position()=$pos]/@value" /></td>
</xsl:when>
<xsl:otherwise>
<td></td>
<td></td>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="$M > $m">
<xsl:call-template name="nmth-cell">
<xsl:with-param name="n" select="$n" />
<xsl:with-param name="m" select="$m + 1" />
<xsl:with-param name="N" select="$N" />
<xsl:with-param name="M" select="$M" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:transform>
匹配/DataSet
会生成根元素<report />
并继续应用模板。
从Data
内部匹配/DataSet
会为每个<table />
元素生成<Data />
,然后通过调用名为nth-row
的模板启动有趣的部分。使用的变量和参数是:
@columns
除以2计算的列数,因为每个<item />
会产生两个<td />
元素。<item />
元素的数量计算并除以 M 。要考虑div
截断整数值,余额$count mod $M
之前会添加到$count
。现在出现了一些递归模板调用。每次调用nth-row
时,它都会输出<tr />
,然后使用适当的参数调用nmth-cell
。只要当前行不是最后一行,nth-row
将以$n
的递增值递归调用。
最后,模板nmth-cell
每次调用时都会输出两个包含相应<td />
值的<item />
元素,如果没有相应的<item />
则不输出}。只要当前列不是最后一列,nmth-cell
将以递增的值$m
递归调用。
我希望这会有所帮助。如果有任何问题或者您不清楚,请随意询问。
答案 1 :(得分:1)
这是一个更简单的解决方案。
此XSLT 1.0样式表......
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:template match="/*">
<report>
<xsl:apply-templates />
</report>
</xsl:template>
<xsl:template match="Data">
<xsl:variable name="cols" select="@columns" />
<table>
<xsl:for-each select="item[position()*2 mod $cols = (2 mod $cols)]">
<tr>
<xsl:for-each select="(.|following-sibling::item)
[ position()*2 <= $cols]">
<td><xsl:value-of select="@name" /></td>
<td><xsl:value-of select="@value" /></td>
</xsl:for-each>
<xsl:if test="position()=last()">
<xsl:for-each select="((/)//*)[position() <=
($cols - (count(.|following-sibling::item)*2))]">
<td />
</xsl:for-each>
</xsl:if>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
...应用于此输入时...
<DataSet>
<Data id ="1" columns ="4">
<item name ="data1" value="value1"/>
<item name ="data2" value="value2"/>
<item name ="data3" value="value3"/>
<item name ="data4" value="value4"/>
<item name ="data5" value="value5"/>
</Data>
<Data id="2" columns ="2">
<item name ="data1" value="value1"/>
<item name ="data2" value="value2"/>
<item name ="data3" value="value3"/>
<item name ="data4" value="value4"/>
</Data>
</DataSet>
<强> ...产量... 强>
<report>
<table>
<tr>
<td>data1</td>
<td>value1</td>
<td>data2</td>
<td>value2</td>
</tr>
<tr>
<td>data3</td>
<td>value3</td>
<td>data4</td>
<td>value4</td>
</tr>
<tr>
<td>data5</td>
<td>value5</td>
<td></td>
<td></td>
</tr>
</table>
<table>
<tr>
<td>data1</td>
<td>value1</td>
</tr>
<tr>
<td>data2</td>
<td>value2</td>
</tr>
<tr>
<td>data3</td>
<td>value3</td>
</tr>
<tr>
<td>data4</td>
<td>value4</td>
</tr>
</table>
</report>
position()
将输出结构化为矩阵。这比具有许多参数的错综复杂的调用模板更为可取。html
输出方法而不是默认的xml
输出方法。这为您提供了空元素的html编码风格(例如<td></td>
over xml style </td>
)。答案 2 :(得分:0)
我不知道你想要什么样的格式,但这应该让你接近我希望。它为每个数据集创建一个表,其中数据和值对彼此相邻。如果您还需要格式化帮助,请发表评论
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<report>
<xsl:for-each select="DataSet/Data">
<table>
<xsl:for-each select="item">
<tr>
<td><xsl:value-of select="@name"/></td>
<td><xsl:value-of select="@value"/></td>
</tr>
</xsl:for-each>
</table>
</xsl:for-each>
</report>
</body>
</html>
</xsl:template>