2

I'm looking for an XSL to sort and group an XML by a node and sum by another node. I will have to use XSLT 1.0.

Here is my XML. After sorting I need to have a new XML sorted and Grouped by <TransCode>, and all <TransAmt> should be summed for each group. I'm looking for the XSL for this task. Any help is appreciated. After sorting new XML should have only three nodes sorted in ascending order of <TransCode>. All the <TransAmt> must be added together.

Here is my XML:

<Transactions>
 <Transaction>
  <TransCode>0008</TransCode>
  <TransType>Purchase</TransType>
  <TransAmt>12.30</TransAmt>
 </Transaction>

 <Transaction>
  <TransCode>0002</TransCode>
  <TransType>Cash</TransType>
  <TransAmt>26.00</TransAmt>
 </Transaction>

 <Transaction>
  <TransCode>0008</TransCode>
  <TransType>Purchase</TransType>
  <TransAmt>25.00</TransAmt>
 </Transaction>

 <Transaction>
  <TransCode>0015</TransCode>
  <TransType>FinanceCharge</TransType>
  <TransAmt>25.00</TransAmt>
 </Transaction>

 <Transaction>
  <TransCode>0002</TransCode>
  <TransType>Cash</TransType>
  <TransAmt>50.00</TransAmt>
 </Transaction>

 <Transaction>
  <TransCode>0008</TransCode>
  <TransType>Purchase</TransType>
  <TransAmt>40.00</TransAmt>
 </Transaction>
</Transactions>
2
  • Are you asking us to write your XSL for you? Perhaps you can post the XSL you have come up with and tell us what issues and problems you have with it? A sample of the output document you want will also help with answering the question. Commented Aug 15, 2010 at 16:13
  • Good question (+1). See my answer for a complete and efficient solution and explanation of the key ideas. :) Commented Aug 15, 2010 at 19:22

2 Answers 2

1

This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"  />

 <xsl:key name="kTransByCode"
     match="Transaction" use="TransCode"/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="/Transactions">
  <Transactions>
   <xsl:apply-templates select=
    "Transaction[generate-id()
                =
                 generate-id(key('kTransByCode',
                                  TransCode
                                  )[1]
                             )
                 ]
    ">
     <xsl:sort select="TransCode" data-type="number"/>
    </xsl:apply-templates>
  </Transactions>
 </xsl:template>

 <xsl:template match="TransAmt">
  <TransAmt>
    <xsl:value-of select=
    "sum(key('kTransByCode',../TransCode)/TransAmt)"/>
  </TransAmt>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<Transactions>
 <Transaction>
  <TransCode>0008</TransCode>
  <TransType>Purchase</TransType>
  <TransAmt>12.30</TransAmt>
 </Transaction>

 <Transaction>
  <TransCode>0002</TransCode>
  <TransType>Cash</TransType>
  <TransAmt>26.00</TransAmt>
 </Transaction>

 <Transaction>
  <TransCode>0008</TransCode>
  <TransType>Purchase</TransType>
  <TransAmt>25.00</TransAmt>
 </Transaction>

 <Transaction>
  <TransCode>0015</TransCode>
  <TransType>FinanceCharge</TransType>
  <TransAmt>25.00</TransAmt>
 </Transaction>

 <Transaction>
  <TransCode>0002</TransCode>
  <TransType>Cash</TransType>
  <TransAmt>50.00</TransAmt>
 </Transaction>

 <Transaction>
  <TransCode>0008</TransCode>
  <TransType>Purchase</TransType>
  <TransAmt>40.00</TransAmt>
 </Transaction>
</Transactions>

produces the wanted, correct result:

<Transactions>
   <Transaction>
      <TransCode>0002</TransCode>
      <TransType>Cash</TransType>
      <TransAmt>76</TransAmt>
   </Transaction>
   <Transaction>
      <TransCode>0008</TransCode>
      <TransType>Purchase</TransType>
      <TransAmt>77.3</TransAmt>
   </Transaction>
   <Transaction>
      <TransCode>0015</TransCode>
      <TransType>FinanceCharge</TransType>
      <TransAmt>25</TransAmt>
   </Transaction>
</Transactions>

Do note:

  1. The Muenchian method for grouping is used.

  2. The use of keys allows for easy and efficient summation per transcode.

  3. The identity rule is used to copy as-is most elements and is overridden by templates matching elements that will be different in the output.

Sign up to request clarification or add additional context in comments.

1 Comment

+1 Good answer! But, Ithink it could be less verbose if you match the "first in a kind" Transaction and TransAmt/text(). I'm saying this because some people complain about XSLT been verbose, you know.
0

XSL has built in sorting through the <xsl:sort> element, and summing using the XPath sum function.

Both are supported in XSLT 1.0.

What are the issues you are having using these?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.