我有以下XML:
<cars>
<car type='toyota'>
<model>Yaris</model>
<year>1998</year>
<company>TOYOTA</company>
</car>
<car type='kia'>
<model>Optima</model>
<year>2002</year>
<company>KIA</company>
</car>
<car type='kia'>
<model>CERATO</model>
<year>2009</year>
<company>KIA</company>
</car>
<car type='bmw'>
<model>M3</model>
<year>2016</year>
<company>BMW</company>
</car>
<car type='bmw'>
<model>X5</model>
<year>2010</year>
</car>
<car type='bmw'>
<model>335i</model>
<year>2010</year>
<company>BMW</company>
</car>
</cars>
我想按公司元素对汽车进行分组,并对同一元素进行排序(字母,升序)。输出应该是这样的:
BMW: M3, X5, 335i
KIA: Optima, CERATO
TOYOTA: Yaris
问题是car元素可能不包含公司节点,在这种情况下,必须使用car / @ type值将元素添加到正确的组中。如何将@type属性的值映射到基于公司价值的正确组?
答案 0 :(得分:0)
XSLT的一个鲜为人知的功能(至少在2.0版中)是
当您创建列表时,例如(xx, yy, zz)
,此列表
实际上只包含仅现有值。
如果例如xx
值是空的,它不会成为
结果列表。
因此,如果您在其后写上[1]
,实际上您会得到
括号之间的表达式列表中的非空元素。
在您的评论中,自5.08起,您要求输入other
类型的解决方案
应该被视为TOYOTA
。
在这种情况下,可以使用if ... then ... else ...
:
如果(@type ='other'),然后是'TOYOTA'else @type
因此,您可以通过以下方式编写脚本:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="cars">
<xsl:for-each-group select="car" group-by="upper-case(
(company, if (@type = 'other') then 'TOYOTA' else @type)[1])">
<xsl:sort select="current-grouping-key()"/>
<xsl:value-of select="current-grouping-key()"/>
<xsl:text>: </xsl:text>
<xsl:value-of select="string-join(current-group()/model, ', ')"/>
<xsl:text>
</xsl:text>
</xsl:for-each-group>
</xsl:template>
</xsl:transform>
如您所见:
(company, if (@type = 'other') then 'TOYOTA' else @type)
是源列表(大写字母的参数),[1]
从创建的内容中提取第一个元素。我将对upper-case
的呼叫移到了“外层”,
假设model
也可以小写。