Reputation: 43
I am looking for XSLT to sum quantities with same date only once when traversing through the xml file.
Input:
<root>
<interval>
<mn>
<quantity>1</quantity>
<date>2015-03-14</date>
<ccode>102010</ccode>
</mn>
<mn>
<quantity>2</quantity>
<date>2015-03-15</date>
<ccode>202010</ccode>
</mn>
</interval>
<interval>
<mn>
<quantity>1</quantity>
<date>2015-03-15</date>
<ccode>202000</ccode>
</mn>
<mn>
<quantity>2</quantity>
<date>2015-03-17</date>
<ccode>302010</ccode>
</mn>
</interval>
<interval>
<mn>
<quantity>5</quantity>
<date>2015-03-14</date>
<ccode>102000</ccode>
</mn>
<mn>
<quantity>3</quantity>
<date>2015-03-18</date>
<ccode>402010</ccode>
</mn>
</interval>
</root>
Expected Output:
<mn>
<quantity>6</quantity>
<date>2015-03-14</date>
<ccode>102000</ccode>
</mn>
<mn>
<quantity>3</quantity>
<date>2015-03-15</date>
<ccode>202000</ccode>
</mn>
<mn>
<quantity>2</quantity>
<date>2015-03-17</date>
<ccode>302010</ccode>
</mn>
<mn>
<quantity>3</quantity>
<date>2015-03-18</date>
<ccode>402010</ccode>
</mn>
The quantities are added when date matches. Problem with my xslt is it traverses every mn node in first interval node, sums up quantities for same date from all interval nodes, then it traverses second interval and sums up quantities "again from all interval nodes". I want the sum of quantities for one date only once. CCODE value should be the least/minimum of all the values for a date. My XSLT is as below:
<xsl:template match="/">
<xsl:for-each select="root/interval/mn">
<xsl:variable name="dtt" select="date"/>
<xsl:variable name="qty" select="sum(../../interval/mn[date = $dtt]/quantity)"/>
</xsl:for-each>
Upvotes: 3
Views: 222
Reputation: 21661
You're most of the way there - just need to use Muenchian grouping (define an xsl:key
) have your for-each
select each date node only once.
XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="mnByDate" match="mn" use="date" />
<xsl:template match="/">
<root>
<xsl:for-each select="root/interval/mn[count(. | key('mnByDate', date)[1]) = 1]">
<xsl:variable name="dtt" select="date"/>
<xsl:variable name="ccode" select="ccode"/>
<xsl:variable name="qty" select="sum(../../interval/mn[date = $dtt]/quantity)"/>
<mn>
<quantity>
<xsl:value-of select="$qty"/>
</quantity>
<date>
<xsl:value-of select="$dtt" />
</date>
<ccode>
<xsl:value-of select="//mn[date = $dtt]/ccode[not(. > //mn[date = $dtt]/ccode)][1]" />
</ccode>
</mn>
</xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>
Output:
<?xml version="1.0" encoding="utf-8"?>
<root>
<mn>
<quantity>6</quantity>
<date>2015-03-14</date>
<ccode>102000</ccode>
</mn>
<mn>
<quantity>3</quantity>
<date>2015-03-15</date>
<ccode>202000</ccode>
</mn>
<mn>
<quantity>2</quantity>
<date>2015-03-17</date>
<ccode>302010</ccode>
</mn>
<mn>
<quantity>3</quantity>
<date>2015-03-18</date>
<ccode>402010</ccode>
</mn>
</root>
Upvotes: 2