我的XML源代码如下:
<query>
<Rows>
<Row ID="1" name="person1" title="p1package1" />
<Row ID="2" name="person1" title="p1package2" />
<Row ID="3" name="person2" title="p2package1" />
</Rows>
</query>
我想用XSL创建一个输出:
<table>
<tr>
<td>person1</td>
<td>p1package1, p1package2</td>
</tr>
<tr>
<td>person2</td>
<td>p2package1</td>
</tr>
</table>
我尝试使用以下XSL-sylesheet,但在第一个之前打开似乎导致无效的结构,因此页面无法加载。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output version="1.0" indent="yes" encoding="UTF-8" method="xml" />
<xsl:template match='query'>
<table>
<xsl:for-each select="Rows/Row" >
<xsl:if test="preceding-sibling::Row/@name != @name or position() = 1">
<tr>
<td><xsl:value-of select="@name" /></td>
<td>
</xsl:if>
<xsl:value-of select="@title" />
<xsl:if test="not(following-sibling::Row/@name = @name)">
</td>
</tr>
</xsl:if>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
我怎么能接近这个?我知道XML的结构不是很好,但我对数据源没有影响。
答案 0 :(得分:2)
为了完整性,这里是XSLT 2.0中的等价物
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output version="1.0" indent="yes" encoding="UTF-8" method="xml" />
<xsl:template match='query'>
<table>
<xsl:for-each-group select="Rows/Row" group-by="@name">
<tr>
<td><xsl:value-of select="@name"/></td>
<td><xsl:value-of select="current-group()/@title" separator=", "/></td>
</tr>
</xsl:for-each-group>
</table>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:1)
在XSLT 1.0中对此类问题进行分组的标准方法是 Muenchian分组 - 您定义了一个按照您希望的方式对项目进行分组的密钥,然后使用generate-id()
技巧来处理只是带有每个键值的第一个项。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output version="1.0" indent="yes" encoding="UTF-8" method="xml" />
<xsl:key name="rowByName" match="Row" use="@name" />
<xsl:template match="/">
<table>
<!-- apply templates for the first Row with each name -->
<xsl:apply-templates select="query/Rows/Row[generate-id() =
generate-id(key('rowByName', @name)[1])]" />
</table>
</xsl:template>
<xsl:template match="Row">
<tr>
<td><xsl:value-of select="@name" /></td>
<td>
<!-- concatenate the title attributes of all rows with this name -->
<xsl:for-each select="key('rowByName', @name)">
<xsl:if test="position() > 1">, </xsl:if>
<xsl:value-of select="@title" />
</xsl:for-each>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>