Home > Mobile >  XSLT 1.0 Aggregate and select distinct key and sum
XSLT 1.0 Aggregate and select distinct key and sum

Time:08-11

I'm fairly new to XSLT, I've been trying to piece some of the other examples posted on this topic but I still can't quite get it right

This is an example of my XML

<?xml version="1.0" encoding="UTF-8"?>
<customers>
   <customer>
      <customerID>1234</customerID>
      <invoiceNo>5698</invoiceNo>
      <amount>1000.00</amount>
   </customer>
   <customer>
      <customerID>7755</customerID>
      <invoiceNo>7864</invoiceNo>
      <amount>1500.00</amount>
   </customer>
   <customer>
      <customerID>1234</customerID>
      <invoiceNo>3697</invoiceNo>
      <amount>800.00</amount>
   </customer>
</customers>

The result I'm looking for is this

<?xml version="1.0"?>
<customers>
    <customer>
        <customerID>1234</customerID>
        <totalAmount>1800</totalAmount>
    </customer>
    <customer>
        <customerID>7755</customerID>
        <totalAmount>1500</totalAmount>
    </customer>
</customers>

This is my current XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" indent="yes" />

<xsl:key name="kCustomer" match="customer" use="customerID" />

<xsl:template match="customers">
<customers>
<xsl:apply-templates select="customer[generate-id()=generate-id(key('kCustomer',customerID[1])]"/>
</customers>
</xsl:template>
    
<xsl:template match="customer" >
<customer>
<xsl:for-each select="key('kCustomer', customerID)">
<customerID><xsl:value-of select="key('kCustomer',customerID)/customerID"/></customerID>
<totalAmount><xsl:value-of select="sum(key('kCustomer', customerID)/amount)" /></totalAmount>
</xsl:for-each>
</customer>
            
</xsl:template>
</xsl:stylesheet>`

It's giving me the SUM value but it's printing duplicates based on the numbers of invoices.

<?xml version="1.0"?>
<customers>
    <customer>
        <customerID>1234</customerID>
        <totalAmount>1800</totalAmount>
        <customerID>1234</customerID>
        <totalAmount>1800</totalAmount>
    </customer>
    <customer>
        <customerID>7755</customerID>
        <totalAmount>1500</totalAmount>
    </customer>
</customers>

Any pointers would be appreciated

CodePudding user response:

Change:

<xsl:template match="customer" >
<customer>
<xsl:for-each select="key('kCustomer', customerID)">
<customerID><xsl:value-of select="key('kCustomer',customerID)/customerID"/></customerID>
<totalAmount><xsl:value-of select="sum(key('kCustomer', customerID)/amount)" /></totalAmount>
</xsl:for-each>
</customer>
            
</xsl:template>

to:

<xsl:template match="customer">
<customer>
<xsl:copy-of select="customerID"/>
<totalAmount><xsl:value-of select="sum(key('kCustomer', customerID)/amount)" /></totalAmount>
</customer>
</xsl:template>

For better understanding, read the original article: http://www.jenitennison.com/xslt/grouping/muenchian.html


P.S. Indentation improves readability.

CodePudding user response:

This is a grouping query: a search for "XSLT grouping" will give you lots of information. Grouping becomes very easy in XSLT 2.0 using the xsl:for-each-group instruction, but in 1.0 you need to use an obscure workaround called "Muenchian grouping" (after its inventor, Steve Muench) - @michael.hor257k has shown you an example using this approach.

But it's best to move to XSLT 2.0 or 3.0 if you can - lots of things become easier.

  • Related