假设我有以下列表:
<list>
<item>text1</item>
<item>text2</item>
<item>text3</item>
<item type="type1">text4</item>
<item type="type1">text5</item>
<item type="type1">text6</item>
<item>text7</item>
<item>text8</item>
<item type="type2">text9</item>
<item type="type2">text10</item>
<item>text11</item>
<item>text12</item>
<item type="...">...</item>
...
<item>...</item>
...
</list>
重要的一点是,我不知道什么值会有类型属性!它将以编程方式生成。不是这个。我只知道有些项目可能具有相同的属性
我想把这个列表转换成:
text1
text2
text3
text4, text5, text6
text7
text8
text9, text10
text11
text12
所以,对于每个并没有"type"属性的项,我只输出项中的文本。对于每个具有相同属性的项目,我在一行中输出所有项目文本。如何在xslt中实现这一点?当属性以编程方式生成时,如何选择具有相同属性的所有项?
您希望按类型对项目进行分组。分组很容易用一个键完成:
<xsl:key name="byType" match="item[@type]" use="@type" />
这将创建具有类型的所有项的索引,使用它们各自的类型作为键。
接下来,只有当以下两个条件之一为真时,才需要生成输出行:
- 项目没有类型,或者
- 该项目是其类型中的第一个
可以表示为:
<xsl:if test="not(@type) or generate-id() = generate-id(key('byType', @type)[1])">
其类型的第一个项目将输出所有其他项目,这些项目用逗号分隔。以下相同类型的项目不应输出任何内容(因为它们已经打印)。
我们可以将要在每行打印的项目列表定义为这两个节点集的并集:
- 当前项目(对于项目没有类型的情况)
- 与当前项目具有相同类型的所有项目(通过键)
在XPath中,这是. | key('byType', @type)
(节点集永远不能两次包含同一节点)
所以这个:
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8" />
<xsl:key name="byType" match="item[@type]" use="@type" />
<xsl:template match="/*">
<xsl:apply-templates select="item" />
</xsl:template>
<xsl:template match="item">
<xsl:if test="not(@type) or generate-id() = generate-id(key('byType', @type)[1])">
<xsl:for-each select=". | key('byType', @type)">
<xsl:value-of select="." />
<xsl:if test="position() < last()">, </xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:if>
</xsl:template>
</xsl:transform>
输出
文本1文本2文本3text4、text5、text6文本7文本8text9,text10文本11文本12。。。。。。
您想要使用Muenchian分组。像这样的东西应该工作
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:key name="items-by-type" match="item" use="@type" />
<xsl:template match="/list">
<xsl:for-each select="item[count(. | key('items-by-type', @type)[1]) = 1]">
<xsl:if test="not(@type)">
<xsl:value-of select="."/>
<xsl:text> </xsl:text>
</xsl:if>
<xsl:if test="@type">
<xsl:for-each select="key('items-by-type', @type)">
<xsl:value-of select="." />
<xsl:if test="position() != last()"><xsl:text>, </xsl:text></xsl:if>
</xsl:for-each>
<xsl:text> </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:transform>
http://xsltransform.net/3NJ3914/3
使用key
对item
s进行分组。如果未设置@type
,则只打印项目。否则,迭代该@type
的所有item
并打印它们。