I need to get unique role
with bar
as child nodes where role/@totalQty
is sum of all qty
for that role
. This has to be in 1 template using XSLT 1.0
I have written the following code. Is there a better way I can do it with lesser loops as I am looping 4 times , twice in for-loop
,once in sum
& once in key
?
Input
<foo>
<bar qty="1" unit="123">
<var role="abc"/>
</bar>
<bar qty="1" unit="123">
<var role="efg"/>
</bar>
<bar qty="2" unit="501">
<var role="efg"/>
</bar>
<bar qty="1" unit="123">
<var role="efg"/>
</bar>
<bar qty="1" unit="123">
<var role="abc"/>
</bar>
<bar qty="1" unit="9085">
<var role="abc"/>
</bar>
</foo>
Output
<foo>
<vars>
<var role="abc" totalQty="3">
<bar qty="1" unit="123" />
<bar qty="1" unit="123" />
<bar qty="1" unit="9085" />
</var>
<var role="efg" totalQty="4">
<bar qty="1" unit="123" />
<bar qty="2" unit="501" />
<bar qty="1" unit="123" />
</var>
</vars>
</foo>
xslt 1.0
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:key name="uniquerole" match="//bar/var" use="@role"/>
<xsl:template match="/">
<foo>
<vars>
<xsl:for-each select="//bar/var[generate-id() = generate-id(key('uniquerole', @role))]">
<xsl:variable name="vRole">
<xsl:value-of select="@role"/>
</xsl:variable>
<xsl:variable name="tot_qty">
<xsl:value-of select="sum(//bar[var/@role=$vRole]/@qty)"/>
</xsl:variable>
<var>
<xsl:attribute name="role">
<xsl:value-of select="$vRole"/>
</xsl:attribute>
<xsl:attribute name="totalQty">
<xsl:value-of select="$tot_qty"/>
</xsl:attribute>
<xsl:for-each select="//bar[var/@role=$vRole]">
<bar>
<xsl:attribute name="qty">
<xsl:value-of select="@qty"/>
</xsl:attribute>
<xsl:attribute name="unit">
<xsl:value-of select="@unit"/>
</xsl:attribute>
</bar>
</xsl:for-each>
</var>
</xsl:for-each>
</vars>
</foo>
</xsl:template>
</xsl:stylesheet>
CodePudding user response:
Why not simply:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="bar-by-role" match="bar" use="var/@role"/>
<xsl:template match="/foo">
<foo>
<vars>
<xsl:for-each select="bar[generate-id() = generate-id(key('bar-by-role', var/@role)[1])]">
<xsl:variable name="grp" select="key('bar-by-role', var/@role)" />
<var role="{var/@role}" totalQty="{sum($grp/@qty)}">
<xsl:for-each select="$grp">
<bar qty="{@qty}" unit="{@unit}"/>
</xsl:for-each>
</var>
</xsl:for-each>
</vars>
</foo>
</xsl:template>
</xsl:stylesheet>