XSLT should only process nodes with the same date once

I am looking for XSLT for summing quantities with the same date only once when going through an 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 Result:

    <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 quantity is added when the date matches. The problem with my xslt is that it traverses every mn node in the first interval node, sums the quantities for the same date from all interval nodes, then crosses the second interval and sums the "again from all interval nodes" quantities. I want the sum of the quantities for one date to be only once. CCODE must be the smallest / smallest for all date values. My XSLT looks like this:

    <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>

      

+3


source to share


1 answer


You are most on the way - just need to use Muenchian grouping (specify xsl:key

) so that yours for-each

selects each node date 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>

      

+2


source







All Articles