我有一个与此类似的XML:
<Test>
<grapes>
<a>TypeA</a>
<b>value1</b>
</grapes>
<oranges>
<a>TypeB</a>
<b>value2</b>
</oranges>
<apples>
<a>TypeA</a>
<b>value3</b>
</apples>
</Test>
其中值是唯一的但类型可能相同。
我正在尝试对其进行排序,以使输出类似于:
<group type="TypeA">
<value v="value1" />
<value v="value3" />
</group>
<group type="TypeB">
<value v="value2" />
</group>
我很难确保这些组在输出中是唯一的,而且值在正确的组中。
我的XSL应该如何构建?
答案 0 :(得分:2)
这是一个更简单的解决方案(完全“推送式”,没有<xsl:for-each>
,没有嵌套,没有<xsl:variable>
,没有current()
,没有{ {1}},没有轴):
//
将此转换应用于提供的XML文档:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kGoodsByType" match="/*/*" use="a"/>
<xsl:template match=
"/*/*[generate-id()
=
generate-id(key('kGoodsByType', a)[1])
]
">
<group type="{a}">
<xsl:apply-templates select="key('kGoodsByType', a)/b"/>
</group>
</xsl:template>
<xsl:template match="b">
<value v="{.}"/>
</xsl:template>
<xsl:template match="*/* | text()" priority="-1"/>
</xsl:stylesheet>
产生了想要的正确结果:
<Test>
<grapes>
<a>TypeA</a>
<b>value1</b>
</grapes>
<oranges>
<a>TypeB</a>
<b>value2</b>
</oranges>
<apples>
<a>TypeA</a>
<b>value3</b>
</apples>
</Test>
解释:<group type="TypeA">
<value v="value1"/>
<value v="value3"/>
</group>
<group type="TypeB">
<value v="value2"/>
</group>
/*/*
使用a
个孩子的字符串值作为关键字。
<强> II。 XSLT 2.0解决方案:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*">
<xsl:for-each-group select="*/a" group-by=".">
<group type="{current-grouping-key()}">
<xsl:sequence select="current-group()/../b"/>
</group>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
在同一个XML文档(上面)上执行此转换时,会生成相同的正确结果:
<group type="TypeA">
<b>value1</b>
<b>value3</b>
</group>
<group type="TypeB">
<b>value2</b>
</group>
<强>解释强>:
<xsl:for-each-group>
current-group()
current-grouping-key()
答案 1 :(得分:1)
XSLT 1.0:
首先,使用muenchian方法为类型创建唯一的组。谷歌它找出它是什么。然后,只需迭代它们并打印出你想要的东西,你想要它:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="types" match="a" use="text()"/>
<xsl:template match="/">
<result>
<xsl:for-each select="//a[generate-id(.) = generate-id(key('types', text())[1])]">
<group type="{current()/text()}">
<xsl:for-each select="//a[text() = current()/text()]">
<xsl:variable name="values" select="following-sibling::b | preceding-sibling::b"/>
<xsl:for-each select="$values">
<value v="{current()}"/>
</xsl:for-each>
</xsl:for-each>
</group>
</xsl:for-each>
</result>
</xsl:template>
</xsl:stylesheet>
您会发现输出与您期望的相同。
答案 2 :(得分:0)
我的建议与FailedDev略有不同:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/Test">
<root>
<xsl:for-each select="*[a != following::a]">
<xsl:sort select="a" data-type="text" />
<group type="{a}">
<xsl:for-each select="/Test/*[a = current()/a]">
<xsl:sort select="b" data-type="text" />
<value v="{b}" />
</xsl:for-each>
</group>
</xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>
外部
<xsl:for-each select="*[a != following::a]" />
选择所有唯一类型,即。 TypeA 和 TypeB 。 在
<xsl:sort select="a" data-type="text" />
根据名称对这些进行排序,确保 TypeA 出现在 TypeB 之上。 内在的
<xsl:for-each select="/Test/*[a = current()/a]" />
为每种类型选择唯一值列表,即。对于 TypeA ,提取值 value1 和 value3 。同样,结果列表在 value3 之前排序为列出 value1 。