Search code examples
xmlxsltxslt-2.0

How to get the Sub total at each row of the group using XSLT


I got a special requirement to show the Sub total at individual row of the group. I tried to rundown each row and using for-each-group function I grouped at Supplier Invoice number. But the results are showing just individual row value instead of subtotal amount. Can you guys show some lite here on how we can achieve this kind of requirement?

Sample Records:

    <Report_Data>
        <Report_Entry>
            <Supplier_Invoice_Number>SINV-01</Supplier_Invoice_Number>
            <Supplier_Invoice_Line>1</Supplier_Invoice_Line>
            <Memo>SC0590</Memo>
            <Amount>10</Amount>
        </Report_Entry>
        <Report_Entry>
            <Supplier_Invoice_Number>SINV-01</Supplier_Invoice_Number>
            <Supplier_Invoice_Line>2</Supplier_Invoice_Line>
            <Memo>SC0590</Memo>
            <Amount>-100</Amount>
        </Report_Entry>
        <Report_Entry>
            <Supplier_Invoice_Number>SINV-02</Supplier_Invoice_Number>
            <Supplier_Invoice_Line>1</Supplier_Invoice_Line>
            <Memo>SC0590</Memo>
            <Amount>10</Amount>
        </Report_Entry>
        <Report_Entry>
            <Supplier_Invoice_Number>SINV-02</Supplier_Invoice_Number>
            <Supplier_Invoice_Line>2</Supplier_Invoice_Line>
            <Memo>SC0590</Memo>
            <Amount>10</Amount>
        </Report_Entry>
    </Report_Data>

Expected Output:

    <Report_Data>
        <Report_Entry>
            <Supplier_Invoice_Number>SINV-01</Supplier_Invoice_Number>
            <Supplier_Invoice_Line>1</Supplier_Invoice_Line>
            <Memo>SC0590</Memo>
            <Amount>10</Amount>
            <SubTotal>-90</SubTotal>
        </Report_Entry>
        <Report_Entry>
            <Supplier_Invoice_Number>SINV-01</Supplier_Invoice_Number>
            <Supplier_Invoice_Line>2</Supplier_Invoice_Line>
            <Memo>SC0590</Memo>
            <Amount>-100</Amount>
            <SubTotal>-90</SubTotal>
        </Report_Entry>
        <Report_Entry>
            <Supplier_Invoice_Number>SINV-02</Supplier_Invoice_Number>
            <Supplier_Invoice_Line>1</Supplier_Invoice_Line>
            <Memo>SC0590</Memo>
            <Amount>10</Amount>
            <SubTotal>20</SubTotal>
        </Report_Entry>
        <Report_Entry>
            <Supplier_Invoice_Number>SINV-02</Supplier_Invoice_Number>
            <Supplier_Invoice_Line>2</Supplier_Invoice_Line>
            <Memo>SC0590</Memo>
            <Amount>10</Amount>
            <SubTotal>20</SubTotal>
        </Report_Entry>
    </Report_Data>

XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        exclude-result-prefixes="xs"
        version="2.0">
        <xsl:output method="xml" indent="yes"/>
        <xsl:template match="Report_Data">
            <Report_Data>
                <xsl:for-each select="Report_Entry">
                    <Report_Entry>
                        <xsl:copy-of select="Supplier_Invoice_Number"/>
                        <xsl:copy-of select="Supplier_Invoice_Line"/>
                        <xsl:copy-of select="Memo"/>
                        <xsl:copy-of select="Amount"/>
                        <SubTotal>
                            <xsl:for-each-group select="." group-by="Supplier_Invoice_Number">
                            <xsl:value-of select="sum(Amount)"/>
                            </xsl:for-each-group>
                        </SubTotal>
                    </Report_Entry>
                </xsl:for-each>
            </Report_Data>
            
        </xsl:template>
        
    </xsl:stylesheet>

Solution

  • I think this will produce the output you expect:

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    
    <xsl:template match="/Report_Data">
        <Report_Data>
            <xsl:for-each-group select="Report_Entry" group-by="Supplier_Invoice_Number">
                <xsl:variable name="subtotal" select="sum(current-group()/Amount)" />
                <xsl:for-each select="current-group()">
                    <Report_Entry>
                        <xsl:copy-of select="*"/>
                        <SubTotal>
                            <xsl:value-of select="$subtotal"/>
                        </SubTotal>
                    </Report_Entry>
                </xsl:for-each>
            </xsl:for-each-group>
        </Report_Data>
    </xsl:template>
    
    </xsl:stylesheet>