-1

I am trying to group an xml based upon certain node values:

<bus:TaxList>
<bus:VoPaidTax>
<bus:TaxAmount>4.45</bus:TaxAmount>
<bus:TaxCode>10</bus:TaxCode>
<bus:TaxRate>0.05</bus:TaxRate>
<bus:TaxType>VAT</bus:TaxType>
</bus:VoPaidTax>
<bus:VoPaidTax>
<bus:TaxAmount>6.23</bus:TaxAmount>
<bus:TaxCode>12</bus:TaxCode>
<bus:TaxRate>0.07</bus:TaxRate>
<bus:TaxType>VAT</bus:TaxType>
</bus:VoPaidTax>
<bus:VoPaidTax>
<bus:TaxAmount>6.45</bus:TaxAmount>
<bus:TaxCode>10</bus:TaxCode>
<bus:TaxRate>0.05</bus:TaxRate>
<bus:TaxType>VAT</bus:TaxType>
</bus:VoPaidTax>
<bus:VoPaidTax>
<bus:TaxAmount>9.03</bus:TaxAmount>
<bus:TaxCode>12</bus:TaxCode>
<bus:TaxRate>0.07</bus:TaxRate>
<bus:TaxType>VAT</bus:TaxType>
</bus:VoPaidTax>
</bus:TaxList

Now I want to add VoPaidTax group which have the same TaxCode and Rate.

<bus:TaxList>
<bus:VoPaidTax>
<bus:TaxAmount>10.90</bus:TaxAmount>
<bus:TaxCode>10</bus:TaxCode>
<bus:TaxRate>0.05</bus:TaxRate>
<bus:TaxType>VAT</bus:TaxType>
</bus:VoPaidTax>
<bus:VoPaidTax>
<bus:TaxAmount>15.23</bus:TaxAmount>
<bus:TaxCode>12</bus:TaxCode>
<bus:TaxRate>0.07</bus:TaxRate>
<bus:TaxType>VAT</bus:TaxType>
</bus:VoPaidTax>
</bus:TaxList

And leave the unique ones.

I have tried something like this but it does n't seem to work What am I doing wrong here:

<xsl:template    match="bus:TaxList">
<xsl:for-each select="bus:VoPaidTax[not(bus:TaxCode = ../preceding-  sibling::*/bus:VoPaidTax/bus:TaxCode) and not(bus:TaxRate= ../preceding-  sibling::*/bus:VoPaidTax/bus:TaxRate)]">
<xsl:call-template name="taxCorrection">
<xsl:with-param name="TaxCode">
<xsl:value-of select="bus:TaxCode"/>
</xsl:with-param>
<xsl:with-param name="percent">
<xsl:value-of select="bus:TaxRate"/>
</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</xsl:template>

<xsl:template name="taxCorrection">
<xsl:param name="TaxCode"/>
<xsl:param name="percent"/>
<xsl:variable name="sumTaxRate">
<xsl:value-of select="sum(../bus:VoPaidTax[bus:TaxCode = $TaxCode and bus:TaxRate =$percent]/bus:TaxAmount)" />
</xsl:variable>

</xsl:template>

Thing is this template is getting called multiple times and the sum as well as the preceding-sibling doesn't seem to work. What am I doing wrong here?? I am using XSLT 1.0 Can someone please help me out!

Yauza
  • 180
  • 1
  • 13
  • Grouping in XSLT 1.0 is achieved through a method called Muenchian grouping. Read the article here: http://www.jenitennison.com/xslt/grouping/muenchian.html and see the many examples already posted on SO. – michael.hor257k Oct 24 '15 at 21:10
  • I now see that I have posted an almost exactly the same comment on a previous question of yours: http://stackoverflow.com/questions/32945177/grouping-xml-data-to-multiple-requests#comment53725311_32945177 – michael.hor257k Oct 24 '15 at 21:14
  • I think Muenchian grouping should be used for something where more faster processing is required. But here i will always have less data not that big nad hardly 5-6 elements. Is my approach wrong anywhere? – Yauza Oct 24 '15 at 21:15

2 Answers2

1

Indeed, consider the Muenchian Grouping especially as keys are needed to align figures for group summing.

<xsl:key name="taxgrp" match="bus:VoPaidTax" use="concat(bus:TaxCode, bus:TaxRate)" />

  <xsl:template match="bus:TaxList">
   <bus:TaxList>            
    <xsl:for-each select="bus:VoPaidTax[generate-id()
                 = generate-id(key('taxgrp', concat(bus:TaxCode, bus:TaxRate))[1])]">
       <bus:VoPaidTax>
         <bus:TaxAmount>
           <xsl:value-of select="sum(key('taxgrp', 
                                     concat(bus:TaxCode, bus:TaxRate))/bus:TaxAmount)"/>
         </bus:TaxAmount>
         <xsl:copy-of select="*[not(local-name()='bus:TaxAmount')]"/>
      </bus:VoPaidTax>
    </xsl:for-each>      
   </bus:TaxList>
  </xsl:template>    

Output

<bus:TaxList>
  <bus:VoPaidTax>
    <bus:TaxAmount>10.9</bus:TaxAmount>
    <bus:TaxCode>10</bus:TaxCode>
    <bus:TaxRate>0.05</bus:TaxRate>
    <bus:TaxType>VAT</bus:TaxType>
  </bus:VoPaidTax>
  <bus:VoPaidTax>
    <bus:TaxAmount>15.26</bus:TaxAmount>
    <bus:TaxCode>12</bus:TaxCode>
    <bus:TaxRate>0.07</bus:TaxRate>
    <bus:TaxType>VAT</bus:TaxType>
  </bus:VoPaidTax>
</bus:TaxList>
Parfait
  • 104,375
  • 17
  • 94
  • 125
  • Hi Parfait I have updated my question with the updates after trying out with your solution and tax amount seems to give some different value and also TaxAmount is appearing twice. Thank you so much for the help till now. – Yauza Oct 25 '15 at 10:19
0
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
</xsl:template>
<xsl:key name="taxgrp" match="bus:VoPaidTax" use="concat(generate-id(..),bus:TaxCode, bus:TaxRate)" />

<xsl:template match="bus:BsAddOrderPaymentRequestPayload/bus:Request/bus:TotalPaidAmount/bus:TaxList">

<bus:TaxList>            
<xsl:for-each select="bus:VoPaidTax[generate-id()
             = generate-id(key('taxgrp', concat(generate-id(..),bus:TaxCode, bus:TaxRate))[1])]">
   <bus:VoPaidTax>
     <bus:TaxAmount>
       <xsl:value-of select="sum(key('taxgrp', 
                                 concat(generate-id(..),bus:TaxCode, bus:TaxRate))/bus:TaxAmount)"/>
     </bus:TaxAmount>
     <xsl:copy-of select="*[not(self::bus:TaxAmount)]"/>
  </bus:VoPaidTax>
</xsl:for-each>      
</bus:TaxList>
</xsl:template> 
</xsl:stylesheet>

Added generate-id(..) to each key to keep the grouping in a particular node and not the whole document.

Yauza
  • 180
  • 1
  • 13