Reputation: 40
ich have following XML:
<item>
<number>1</number>
<value>2</value>
</item>
<item>
<number>2</number>
<value>22</value>
</item>
<item>
<number>1</number>
<value>4</value>
</item>
I want to transform the xml with xslt 1.0 to this:
<item>
<number>1</number>
<value>6</value>
</item>
<item>
<number>2</number>
<value>22</value>
</item>
The values from the same item number have to be added up and in the end i want to merge the elements of the same item. There can be n multible items with the same number. In this example the item with the number 1 is two times in the xml so those two will be one entry and the values(2,4) will be added up to 6.
Upvotes: 2
Views: 621
Reputation: 52878
This is a very basic grouping question. In XSLT 1.0, grouping is done by using the Muenchian method.
Start with an identity transform...
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
Group all of the item
's by number
by creating an xsl:key matching item
using number
...
<xsl:key name="items" match="item" use="number"/>
From the context of the parent of all item
's (using doc
as an example), output a copy of the element and apply templates to the first item
in the group (and any attributes)...
<xsl:template match="doc">
<xsl:copy>
<xsl:apply-templates select="@*|item[count(.|key('items',number)[1])=1]"/>
</xsl:copy>
</xsl:template>
Add a template that matches item
and output a copy of it. Apply templates to any attributes and the number
element. Then create a new value
element with the sum of all item
's matching that key...
<xsl:template match="item">
<xsl:copy>
<xsl:apply-templates select="@*|number"/>
<value><xsl:value-of select="sum(key('items',number)/value)"/></value>
</xsl:copy>
</xsl:template>
Full example...
XML Input (added a single root element doc
to make the input well formed)
<doc>
<item>
<number>1</number>
<value>2</value>
</item>
<item>
<number>2</number>
<value>22</value>
</item>
<item>
<number>1</number>
<value>4</value>
</item>
</doc>
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="items" match="item" use="number"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="doc">
<xsl:copy>
<xsl:apply-templates select="@*|item[count(.|key('items',number)[1])=1]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="item">
<xsl:copy>
<xsl:apply-templates select="@*|number"/>
<value><xsl:value-of select="sum(key('items',number)/value)"/></value>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
XML Output
<doc>
<item>
<number>1</number>
<value>6</value>
</item>
<item>
<number>2</number>
<value>22</value>
</item>
</doc>
Upvotes: 4