类似于这个链接xsl sum siblings based on node value,我需要应用一个xsl转换,该转换根据其兄弟节点之一的值对某些节点值求和,问题是有类似的节点我想得到总和因为不同的父母,我无法找出xslt。这是xml的样子。
<?xml version="1.0" encoding="ISO-8859-1" ?>
<Message>
<Body>
<Order>
<Item1>
<.../>
<Type>widget</Type>
<Qty>20</Qty>
<.../>
</Item1>
<Item>
<.../>
<Type>gadget</Type>
<Qty>10</Qty>
<.../>
</Item>
<Item2>
<.../>
<Type>widget</Type>
<Qty>5</Qty>
<.../>
</Item2>
<Item3>
<.../>
<Type>widget</Type>
<Qty>2</Qty>
<.../>
</Item3>
<Item3>
<.../>
<Type>Other</Type>
<Qty>0</Qty>
<.../>
</Item3>
<Item/>
</Order>
</Body>
</Message>
我希望能够通过类型小部件进行分组并得到数量的总和,我的xslt是这样的。
<xsl:value-of select="sum(/Message/Body/Order/Item1|Item2|Item3[Type = 'widget'] /Qty)"/>
我的代码没有给我一个错误,但它也没有返回任何内容。我希望我的输出如下所示,而无需对xml上的类型进行硬编码,例如widget,gadget,因为它也可以更改为其他类型。
小部件总数= 27
小工具总数= 10
我还想从输出中排除包含和等于0的Type。
谢谢! RAF
答案 0 :(得分:0)
试着改为:
<xsl:value-of select="sum(/Message/Body/Order//Qty[preceding-sibling::Type[.='widget']])"/>
<xsl:value-of select="sum(/Message/Body/Order//Qty[preceding-sibling::Type[.='gadget']])"/>
分别产生27
和10
。
修改强>
在xslt-2.0中,您可以使用xsl:for-each-group
,如下所示
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:for-each-group select="/Message/Body/Order/*" group-by="Type">
<xsl:value-of select="concat(current-grouping-key(), ': ')"/>
<xsl:copy-of select="sum(current-group()/Qty)"/>
<xsl:text>
</xsl:text>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
输出:
widget: 27
gadget: 10
Other: 0
答案 1 :(得分:0)
您可以考虑在此处使用key
来查找项目。假设您想要求和的项目始终是order
元素的子项,它们的键将如下所示:
<xsl:key name="item" match="Order/*" use="Type" />
然后总结一下&#34;小部件&#34;项目,你会这样做:
<xsl:value-of select="sum(key('item', 'widget')/Qty)" />
如果你想从输出中排除总数为0的总和,只需使用变量,然后检查
<xsl:variable name="widget" select="sum(key('item', 'widget')/Qty)" />
<xsl:if test="$widget > 0">
<xsl:text>Widget Total = </xsl:text>
<xsl:value-of select="$widget" />
</xsl:if>
如果你想避免硬编码,一种方法是使用xsl:for-each-group
来获取不同的项目,例如:
<xsl:for-each-group select="//Order/*" group-by="Type">
<xsl:variable name="value" select="sum(key('item', Type)/Qty)" />
<xsl:if test="$value > 0">
<xsl:value-of select="Type" />
<xsl:text> Total = </xsl:text>
<xsl:value-of select="$value" />
<xsl:value-of select="' '" />
</xsl:if>
</xsl:for-each-group>
答案 2 :(得分:0)
当前表达式的问题是运算符优先级规则 - 您的XPath
/Message/Body/Order/Item1|Item2|Item3[Type = 'widget']/Qty
解析为
(/Message/Body/Order/Item1)
|
(Item2)
|
(Item3[Type = 'widget']/Qty)
由于您已将问题标记为XSLT-2.0,因此您可以使用括号:
/Message/Body/Order/(Item1|Item2|Item3)[Type = 'widget']/Qty
如果您事先并不知道所有可能的名字,请使用通配符
/Message/Body/Order/*[Type = 'widget']/Qty
至于更一般的问题,这看起来不错。 for-each-group
<xsl:for-each-group select="/Message/Body/Order/*" group-by="Type">
<xsl:variable name="totalQty" select="sum(current-group()/Qty)"/>
<xsl:if test="$totalQty gt 0">
<item type="{current-grouping-key()}" qty="{$totalQty}"/>
</xsl:if>
</xsl:for-each-group>