Manish
Manish

Reputation: 21

XSLT Grouping with SUM issue when first subnode not exists

XML

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="State.xsl" ?>

<StateData>
<States>    
    <State>
        <StateName>State1</StateName>
        <Districts>
            <District>
                <TranslatedDistrictName>AT</TranslatedDistrictName>
                <DistrictName>A</DistrictName>              
                <Population>10000</Population>              
            </District>         
            <District>
                <TranslatedDistrictName>AT</TranslatedDistrictName>
                <DistrictName>B</DistrictName>      
                <Population>5000</Population>                   
            </District>     
            <District>
                <TranslatedDistrictName>AT</TranslatedDistrictName>
                <DistrictName>A</DistrictName>
                <Population>2000</Population>               
            </District>                 
        </Districts>
    </State>
    <State>
        <StateName>State2</StateName>
        <Districts>
            <District>
                <TranslatedDistrictName>AC</TranslatedDistrictName>
                <DistrictName>C</DistrictName>
                <Population>8000</Population>               
            </District>         
            <District>
                <TranslatedDistrictName>AT</TranslatedDistrictName>
                <DistrictName>B</DistrictName>      
                <Population>5500</Population>                   
            </District>     
            <District>
                <TranslatedDistrictName>AP</TranslatedDistrictName>
                <DistrictName>A</DistrictName>
                <Population>1000</Population>               
            </District> 
        </Districts>
    </State>
</States>
</StateData>

XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">  
   <xsl:key name="district-by-state" match="District" use="concat(TranslatedDistrictName,
                       DistrictName[not(string(../TranslatedDistrictName))])" /> 
    <xsl:template match="StateData">
        <xsl:for-each select="States/State">                

                <xsl:for-each select="Districts/District[count(. | key('district-by-state', concat(TranslatedDistrictName,
                       DistrictName[not(string(../TranslatedDistrictName))]))[1]) = 1]">    
                    <hr/>                   
                    - <xsl:value-of select="concat(TranslatedDistrictName,
                       DistrictName[not(string(../TranslatedDistrictName))])"/> 
                     --<xsl:value-of select="sum(key('district-by-state', concat(TranslatedDistrictName,
                        DistrictName[not(string(../TranslatedDistrictName))]))/Population)" />
                </xsl:for-each>
            <hr/>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

Result

As of now, This is working perfect But the moment I add a new state having no district SUM is not working properly.

Note - Added a new State having no Districts tag instead used "District1".

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="State.xsl" ?>

<StateData>
<States>
    <State>
        <StateName>State3</StateName>
        <Districts1>
            <District>
                <TranslatedDistrictName>AT</TranslatedDistrictName>
                <DistrictName>A</DistrictName>              
                <Population>10000</Population>              
            </District>         
            <District>
                <TranslatedDistrictName>AT</TranslatedDistrictName>
                <DistrictName>B</DistrictName>      
                <Population>5000</Population>                   
            </District>     
            <District>
                <TranslatedDistrictName>AT</TranslatedDistrictName>
                <DistrictName>A</DistrictName>
                <Population>2000</Population>               
            </District>                 
        </Districts1>
    </State>
    <State>
        <StateName>State1</StateName>
        <Districts>
            <District>
                <TranslatedDistrictName>AT</TranslatedDistrictName>
                <DistrictName>A</DistrictName>              
                <Population>10000</Population>              
            </District>         
            <District>
                <TranslatedDistrictName>AT</TranslatedDistrictName>
                <DistrictName>B</DistrictName>      
                <Population>5000</Population>                   
            </District>     
            <District>
                <TranslatedDistrictName>AT</TranslatedDistrictName>
                <DistrictName>A</DistrictName>
                <Population>2000</Population>               
            </District>                 
        </Districts>
    </State>
    <State>
        <StateName>State2</StateName>
        <Districts>
            <District>
                <TranslatedDistrictName>AC</TranslatedDistrictName>
                <DistrictName>C</DistrictName>
                <Population>8000</Population>               
            </District>         
            <District>
                <TranslatedDistrictName>AT</TranslatedDistrictName>
                <DistrictName>B</DistrictName>      
                <Population>5500</Population>                   
            </District>     
            <District>
                <TranslatedDistrictName>AP</TranslatedDistrictName>
                <DistrictName>A</DistrictName>
                <Population>1000</Population>               
            </District> 
        </Districts>
    </State>
</States>
</StateData>

Result

Here, SUM for District AT is missing .

Expected Result

AT --22500 AC --8000 AP --1000

Upvotes: 0

Views: 210

Answers (1)

Tim C
Tim C

Reputation: 70648

If you don't want to pick up District elements under Districts1 elements, then one solution is to amend the key to only match District elements under Districts elements

  <xsl:key name="district-by-state" match="Districts/District" use="concat(TranslatedDistrictName,
                   DistrictName[not(string(../TranslatedDistrictName))])" /> 

You might also want to change your xsl:for-each to only select State elements with child Districts nodes

<xsl:for-each select="States/State[Districts]">

Try this XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">  
   <xsl:key name="district-by-state" match="Districts/District" use="concat(TranslatedDistrictName,
                       DistrictName[not(string(../TranslatedDistrictName))])" /> 

    <xsl:template match="StateData">
        <xsl:for-each select="States/State[Districts]">                

                <xsl:for-each select="Districts/District[count(. | key('district-by-state', concat(TranslatedDistrictName,
                       DistrictName[not(string(../TranslatedDistrictName))]))[1]) = 1]">    
                    <hr/>                   
                    - <xsl:value-of select="concat(TranslatedDistrictName,
                       DistrictName[not(string(../TranslatedDistrictName))])"/> 
                     --<xsl:value-of select="sum(key('district-by-state', concat(TranslatedDistrictName,
                        DistrictName[not(string(../TranslatedDistrictName))]))/Population)" />
                </xsl:for-each>
            <hr/>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

Upvotes: 0

Related Questions