Search code examples
xsltelementgroup

Group by multiple elements in XSLT 1.0


Team I have restrained to use XSLT 1.0 as the current-group() method of XSLT version 2.0 is not available in OIC server.

I have the following source

 <ReadResponse>
   <recset>
      <record>
         <date>date1</date>
         <customer_code>cc</customer_code>
         <item>it1</item>
         <uom></uom>
         <qty>5</qty>
         <amount>15</amount>
         <linetype>LINE</linetype>
      </record>
      <record>
         <date>date1</date>
         <customer_code>cc</customer_code>
         <item>it1</item>
         <uom></uom>
         <qty>10</qty>
         <amount>25</amount>
         <linetype>TAX</linetype>
      </record>
        <record>
         <date>date2</date>
         <customer_code>cc</customer_code>
         <item>it2</item>
         <uom></uom>
         <qty>70</qty>
         <amount>700</amount>
         <linetype>LINE</linetype>
      </record>
   </recset>
</ReadResponse>

target is as follows ( group by date,customer_code,item ) Target amount is sum of all amount's from group, Target "qty" is from source where linetype='LINE' and unitprice is ttarget amount divide by qty.

    <?xml version = '1.0' encoding = 'UTF-8'?>
<targset>
      <targrec>
         <date>date1</date>
         <custcode>cc</custcode>
         <item>it1</item>
         <amount>40</amount>
         <qty>5</qty>
         <unitprice>8</unitprice>
      </targrec>
      <targrec>
         <date>date1</date>
         <custcode>cc</custcode>
         <item>it2</item>
         <amount>700</amount>
         <qty>70</qty>
         <unitprice>10</unitprice>
      </targrec>
   </targset>

Solution

  • To spell Muechian grouping out for your sample input data:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="1.0">
      
      <xsl:key name="group" match="record" use="concat(date, '|', customer_code, '|', item)"/>
    
      <xsl:output method="xml" indent="yes"/>
      <xsl:strip-space elements="*"/>
    
      <xsl:template match="@* | node()">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
      </xsl:template>
      
      <xsl:template match="ReadResponse">
        <xsl:apply-templates/>
      </xsl:template>
    
      <xsl:template match="recset">
        <targset>
          <xsl:apply-templates select="record[generate-id() = generate-id(key('group', concat(date, '|', customer_code, '|', item))[1])]"/>
        </targset>
      </xsl:template>
      
      <xsl:template match="record">
        <targrec>
          <xsl:apply-templates/>
          <unitprice>
            <xsl:value-of select="sum(key('group', concat(date, '|', customer_code, '|', item))/amount) div qty"/>
          </unitprice>
        </targrec>
      </xsl:template>
      
      <xsl:template match="record/amount">
        <xsl:copy>
          <xsl:value-of select="sum(key('group', concat(../date, '|', ../customer_code, '|', ../item))/amount)"/>
        </xsl:copy>
      </xsl:template>
      
      <xsl:template match="record/qty">
        <xsl:copy>
          <xsl:value-of select="key('group', concat(../date, '|', ../customer_code, '|', ../item))[linetype = 'LINE']/qty"/>
        </xsl:copy>
      </xsl:template>
      
      <xsl:template match="record/customer_code">
        <custcode>
          <xsl:value-of select="."/>
        </custcode>
      </xsl:template>
      
      <xsl:template match="record/uom | record/linetype"/>
    
    </xsl:stylesheet>