Search code examples
sumgroupingxslt-1.0xslt-grouping

Group by element and sum values XSLT


I am new to XSLT and I am stuck on a problem. I've done some searches I read about Muenchian grouping but I do not know how to use it in this prorblem.

I am trying to write code in XSLT to read every teamName and sum the goals of each teams. I am using XML v 1.0

Below is my current data file in XML:

<footballLeague>
    <round num="1">
        <match>
            <local>
                <teamName>AA</teamName>
                <goals>0</goals>
            </local>
            <visitor>
                <teamName>BB</teamName>
                <goals>1</goals>
            </visitor>
        </match>
        <match>
            <local>
                <teamName>CC</teamName>
                <goals>1</goals>
            </local>
            <visitor>
                <teamName>DD</teamName>
                <goals>0</goals>
            </visitor>
        </match>
    </round>
    <round num="2">
        <match>
            <local>
                <teamName>DD</teamName>
                <goals>1</goals>
            </local>
            <visitor>
                <teamName>AA</teamName>
                <goals>1</goals>
            </visitor>
        </match>
        <match>
            <local>
                <teamName>BB</teamName>
                <goals>0</goals>
            </local>
            <visitor>
                <teamName>CC</teamName>
                <goals>1</goals>
            </visitor>
        </match>
    </round>
    <round num="3">
        <match>
            <local>
                <teamName>DD</teamName>
                <goals>0</goals>
            </local>
            <visitor>
                <teamName>BB</teamName>
                <goals>1</goals>
            </visitor>
        </match>
        <match>
            <local>
                <teamName>CC</teamName>
                <goals>0</goals>
            </local>
            <visitor>
                <teamName>AA</teamName>
                <goals>1</goals>
            </visitor>
        </match>
    </round>
    <round num="4">
        <match>
            <local>
                <teamName>BB</teamName>
                <goals>1</goals>
            </local>
            <visitor>
                <teamName>AA</teamName>
                <goals>0</goals>
            </visitor>
        </match>
        <match>
            <local>
                <teamName>DD</teamName>
                <goals>0</goals>
            </local>
            <visitor>
                <teamName>CC</teamName>
                <goals>1</goals>
            </visitor>
        </match>
    </round>
    <round num="5">
        <match>
            <local>
                <teamName>AA</teamName>
                <goals>1</goals>
            </local>
            <visitor>
                <teamName>DD</teamName>
                <goals>1</goals>
            </visitor>
        </match>
        <match>
            <local>
                <teamName>CC</teamName>
                <goals>1</goals>
            </local>
            <visitor>
                <teamName>BB</teamName>
                <goals>1</goals>
            </visitor>
        </match>
    </round>
    <round num="6">
        <match>
            <local>
                <teamName>BB</teamName>
                <goals>1</goals>
            </local>
            <visitor>
                <teamName>DD</teamName>
                <goals>0</goals>
            </visitor>
        </match>
        <match>
            <local>
                <teamName>AA</teamName>
                <goals>1</goals>
            </local>
            <visitor>
                <teamName>CC</teamName>
                <goals>0</goals>
            </visitor>
        </match>
    </round>
</footballLeague>

The output I would like to achieve after running the XSLT is:

Team Name | Goals For | Goals against | Games Won | Tied Matches
    AA    |      4    |        4      |      2    |      2
    BB    |      5    |        2      |      4    |      1
    CC    |      4    |        3      |      3    |      1
    DD    |      2    |        6      |      0    |      2

Any help to get me started would be fantastic!


Solution

  • See if this can get you started:

    XSLT 1.0

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:key name="score" match="local|visitor" use="teamName" />
    
    <xsl:template match="footballLeague">
        <stats> 
            <xsl:for-each select="round/match/*[count(. | key('score', teamName)[1]) = 1]">
                <team>
                    <xsl:copy-of select="teamName"/>
                    <goals-for>
                        <xsl:value-of select="sum(key('score', teamName)/goals)"/>
                    </goals-for>
                    <goals-against>
                        <xsl:value-of select="sum(key('score', teamName)[self::local]/../visitor/goals) + sum(key('score', teamName)[self::visitor]/../local/goals)"/>
                    </goals-against>
                </team>
            </xsl:for-each>
        </stats>
    </xsl:template>
    
    </xsl:stylesheet>
    

    Applied to your example, the result will be:

    <?xml version="1.0" encoding="UTF-8"?>
    <stats>
      <team>
        <teamName>AA</teamName>
        <goals-for>4</goals-for>
        <goals-against>4</goals-against>
      </team>
      <team>
        <teamName>BB</teamName>
        <goals-for>5</goals-for>
        <goals-against>2</goals-against>
      </team>
      <team>
        <teamName>CC</teamName>
        <goals-for>4</goals-for>
        <goals-against>3</goals-against>
      </team>
      <team>
        <teamName>DD</teamName>
        <goals-for>2</goals-for>
        <goals-against>6</goals-against>
      </team>
    </stats>