Search code examples
xmlxsltxslt-1.0xslt-groupingmuenchian-grouping

XSL variable group by


Input XML:

<output>
<queryResults>
    <record id="1">
        <column name="VRIdTask">1319619</column>
        <column name="MSSinergieTaskP">alt</column>
        <column name="VRPlanId">11310224</column>
        <column name="MSSinergieTaskNP">1319575</column>
    </record>
    <record id="2">
        <column name="VRIdTask">1319619</column>
        <column name="MSSinergieTaskP">alt</column>
        <column name="VRPlanId">11310224</column>
        <column name="MSSinergieTaskNP">1319623</column>
    </record>
    <record id="3">
        <column name="VRIdTask">1319648</column>
        <column name="MSSinergieTaskP"/>
        <column name="VRPlanId">11310337</column>
        <column name="MSSinergieTaskNP"/>
    </record>
    <record id="4">
        <column name="VRIdTask">1319652</column>
        <column name="MSSinergieTaskP">1319667</column>
        <column name="VRPlanId">11310281</column>
        <column name="MSSinergieTaskNP">ms</column>
    </record>
    <record id="5">
        <column name="VRIdTask">1319652</column>
        <column name="MSSinergieTaskP">mss2</column>
        <column name="VRPlanId">11310281</column>
        <column name="MSSinergieTaskNP">ms2</column>
    </record>
    <record id="6">
        <column name="VRIdTask">111</column>
        <column name="MSSinergieTaskP">222</column>
        <column name="VRPlanId">333</column>
        <column name="MSSinergieTaskNP">444</column>
    </record>
    <record id="7">
        <column name="VRIdTask">111</column>
        <column name="MSSinergieTaskP">555</column>
        <column name="VRPlanId">333</column>
        <column name="MSSinergieTaskNP">444</column>
    </record>
 </queryResults>
</output>

Desired output XML:

    <CMMD>
        <parameters>
            <t ids="alt,1319575,1319623"/>
            <!--values from record 1 and 2-->
            <!--for match on VRPlan ID get the distinct values from MSSinergieTaskP and MSSInergieTaskNP and concatenate-->
            <action id="11310224"/>
        </parameters>
    </CMMD>
    <CMMD>
        <parameters>
            <t ids="1319667,ms,mss2,ms2"/>
            <!--values from record 4 and 5. record 3 is ignored because doesn't have any values in the 2 tags-->
            <!--here we have no value that repeats itself in the 2 tags from each record so we concatenate every value-->
            <action id="11310281"/>
        </parameters>
    </CMMD>
    <CMMD>
        <parameters>
            <t ids="444,555,222"/>
            <!--values from record 5 and 6. only MSSinergieTaskNP is not unique -->
            <action id="333"/>
        </parameters>
    </CMMD>

Current XSL, which is not working:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="VRID" match="output/queryResults/record/column[@name='VRPlanId']" use="."/>
<xsl:variable name="MSTaskP" select="output/queryResults/record/column[@name='MSSinergieTaskP']"/>
<xsl:variable name="var_vrid" select="output/queryResults/record/column[@name='VRPlanId']"/>
<xsl:variable name="MSTaskNP" select="output/queryResults/record/column[@name='MSSinergieTaskNP']"/>
<xsl:template match="output">
    <queryResults>
        <xsl:apply-templates select="queryResults/record/parameter[@name='VRPlanId']/value[generate-id(.)=generate-id(key('VRID',.)[1])]"/>
    </queryResults>
</xsl:template>
<xsl:template match="queryResults">
    <xsl:for-each select="key('VRID', $var_vrid)">
        <commun_params>
            <value>
                <xsl:value-of select="$MSTaskNP"/>
            </value>
            <value>
                <xsl:value-of select="$MSTaskP"/>
            </value>
        </commun_params>
    </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

The goal is to check that for every distinct VRPlanId value, we build the above structure that concatenes every distinct value from every record (that has match on VRPlanId) from the //column[@name = MSSinergieTask P and MSSinergieTaskNP. My variables don't seem to work. I was thinking on matching on VR Plan ID value, then check with 2 different variables the distinct values from my required tags.

Can you please help me? Thank you!


Solution

  • Please check XSL below (similar example is here XSLT group if condition is matched):

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
        <xsl:output method="xml" /> 
        <xsl:template name="task-attr">
            <!--parameter to filter per VRPlanId-->     
            <xsl:param name="param.VRPlanId"/>              
            <xsl:variable name="var.mstp">                      
                <xsl:for-each select="/output/queryResults/record[column[@name='VRPlanId'] = $param.VRPlanId]">
                    <!--preventing empty blocks and duplicates for MSTP-->          
                    <xsl:if test="string-length(column[@name='MSSinergieTaskP']) &gt;0 and not(preceding::record[column[@name='MSSinergieTaskP']/text() = current()/column[@name='MSSinergieTaskP']/text()])">                   
                        <xsl:value-of select="concat(column[@name='MSSinergieTaskP'], ',')"/>              
                    </xsl:if>                                       
                </xsl:for-each>                             
            </xsl:variable>     
            <xsl:variable name="var.msonpc">                        
                <xsl:for-each select="/output/queryResults/record[column[@name='VRPlanId'] = $param.VRPlanId]">
                    <!--preventing empty blocks and duplicates for MSONPC-->            
                    <xsl:if test="string-length(column[@name='MSSinergieTaskNP']) &gt;0 and not(preceding::record[column[@name='MSSinergieTaskNP']/text() = current()/column[@name='MSSinergieTaskNP']/text()])">                 
                        <xsl:value-of select="concat(column[@name='MSSinergieTaskNP'], ',')"/>                
                    </xsl:if>                                       
                </xsl:for-each>                             
            </xsl:variable>
            <!--concat all non-duplicates MSTP and MSONPC without last delimiter--> 
            <xsl:value-of select="concat($var.mstp, substring($var.msonpc, 1, string-length($var.msonpc)-1))"/>     
        </xsl:template>
    
        <xsl:template match="/">        
            <output>            
                <xsl:for-each select="/output/queryResults/record">             
                    <xsl:if test ="not(preceding::record[column[@name='VRPlanId']/text() = current()/column[@name='VRPlanId']/text()])">                    
                        <xsl:variable name="task.id">                                                   
                            <xsl:call-template name="task-attr">
                                <!--as input parameter put non-duplicate VRPlanId-->                                                            
                                <xsl:with-param name="param.VRPlanId" select="column[@name='VRPlanId']"/>                                                   
                            </xsl:call-template>                                    
                        </xsl:variable>
                        <!--if all non-duplicates MSTP and MSONPC will be blank block Cdo won't be created-->                   
                        <xsl:if test="string-length($task.id) &gt;0">                       
                            <CMMD>                           
                                <parameters>                                
                                    <task>                                                          
                                        <xsl:attribute name="id">                                                       
                                            <xsl:value-of select="$task.id"/>               
                                        </xsl:attribute>                                
                                    </task>                             
                                    <action>                                                            
                                        <xsl:attribute name="id">                                                                           
                                            <xsl:value-of select="column[@name='VRPlanId']"/>                                                               
                                        </xsl:attribute>                                
                                    </action>                                           
                                </parameters>                       
                            </CMMD>                                      
                        </xsl:if>               
                    </xsl:if>           
                </xsl:for-each>                     
            </output>   
        </xsl:template>
    </xsl:stylesheet>
    

    In case of XML below:

    <output>
    <queryResults>
        <record id="1">
            <column name="VRIdTask">1319619</column>
            <column name="MSSinergieTaskP">alt</column>
            <column name="VRPlanId">11310224</column>
            <column name="MSSinergieTaskNP">1319575</column>
        </record>
        <record id="2">
            <column name="VRIdTask">1319619</column>
            <column name="MSSinergieTaskP">alt</column>
            <column name="VRPlanId">11310224</column>
            <column name="MSSinergieTaskNP">1319623</column>
        </record>
        <record id="3">
            <column name="VRIdTask">1319648</column>
            <column name="MSSinergieTaskP"/>
            <column name="VRPlanId">11310337</column>
            <column name="MSSinergieTaskNP"/>
        </record>
        <record id="4">
            <column name="VRIdTask">1319652</column>
            <column name="MSSinergieTaskP">1319667</column>
            <column name="VRPlanId">11310281</column>
            <column name="MSSinergieTaskNP">ms</column>
        </record>
        <record id="5">
            <column name="VRIdTask">1319652</column>
            <column name="MSSinergieTaskP">mss2</column>
            <column name="VRPlanId">11310281</column>
            <column name="MSSinergieTaskNP">ms2</column>
        </record>
        <record id="6">
            <column name="VRIdTask">111</column>
            <column name="MSSinergieTaskP">222</column>
            <column name="VRPlanId">333</column>
            <column name="MSSinergieTaskNP">444</column>
        </record>
        <record id="7">
            <column name="VRIdTask">111</column>
            <column name="MSSinergieTaskP">555</column>
            <column name="VRPlanId">333</column>
            <column name="MSSinergieTaskNP">444</column>
        </record>
     </queryResults>
    </output>
    

    Result will be as below:

    <?xml version="1.0" encoding="UTF-8"?>
    <output>
        <CMMD>
            <parameters>
                <task id="alt,1319575,1319623"/>
                <action id="11310224"/>
            </parameters>
        </CMMD>
        <CMMD>
            <parameters>
                <task id="1319667,mss2,ms,ms2"/>
                <action id="11310281"/>
            </parameters>
        </CMMD>
        <CMMD>
            <parameters>
                <task id="222,555,444"/>
                <action id="333"/>
            </parameters>
        </CMMD>
    </output>