Search code examples
xsltxslt-grouping

XSLT Group by unique parameter


I am trying to convert the Input xml value to Output xml using xslt based on for-each-group logic of RAPID_ID

Input.xml

<?xml version="1.0" encoding="UTF-8" ?>
<Response>
    <Output>
        <ID>1234</ID>
        <CustomerName>KUMAR</CustomerName>
        <BranchName>HARBOUR</BranchName>
        <SchemeName>GOLD</SchemeName>
        <MobileNumber>123456789</MobileNumber>
        <CustomerType>PRIMARY</CustomerType>
        <DedupeFound>NO</DedupeFound>
    </Output>
    <Output>
        <ID>1234</ID>
        <CustomerName>SEAN</CustomerName>
        <BranchName>HARBOUR</BranchName>
        <SchemeName>GOLD</SchemeName>
        <MobileNumber>123456789</MobileNumber>
        <CustomerType>SECONDARY</CustomerType>
        <DedupeFound>YES</DedupeFound>
    </Output>
    <Output>
        <ID>5678</ID>
        <CustomerName>MARK</CustomerName>
        <BranchName>CANTONMENT</BranchName>
        <SchemeName>DIAMOND</SchemeName>
        <MobileNumber>123456789</MobileNumber>
        <CustomerType>PRIMARY</CustomerType>
        <DedupeFound>NO</DedupeFound>
    </Output>
    <Output>
        <ID>5678</ID>
        <CustomerName>STEVE</CustomerName>
        <BranchName>CANTONMENT</BranchName>
        <SchemeName>DIAMOND</SchemeName>
        <MobileNumber>123456789</MobileNumber>
        <CustomerType>SECONDARY</CustomerType>
        <DedupeFound>YES</DedupeFound>
    </Output>
</Response>

My Expected output is

Output.xml

<?xml version="1.0" encoding="UTF-8" ?>
<Response>
    <Output>
        <ID>1234</ID>
        <CustomerName>KUMAR</CustomerName>
        <BranchName>HARBOUR</BranchName>
        <SchemeName>GOLD</SchemeName>
        <MobileNumber>123456789</MobileNumber>
        <DedupeDetails>
            <CustomerType>PRIMARY</CustomerType>
            <CustomerName>KUMAR</CustomerName>
            <DedupeFound>NO</DedupeFound>
        </DedupeDetails>
        <DedupeDetails>
            <CustomerType>SECONDARY</CustomerType>
            <CustomerName>SEAN</CustomerName>
            <DedupeFound>YES</DedupeFound>
        </DedupeDetails>
    </Output>
    <Output>
        <ID>5678</ID>
        <CustomerName>MARK</CustomerName>
        <BranchName>CANTONMENT</BranchName>
        <SchemeName>DIAMOND</SchemeName>
        <MobileNumber>123456789</MobileNumber>
        <DedupeDetails>
            <CustomerType>PRIMARY</CustomerType>
            <CustomerName>MARK</CustomerName>
            <DedupeFound>NO</DedupeFound>
        </DedupeDetails>
        <DedupeDetails>
            <CustomerType>SECONDARY</CustomerType>
            <CustomerName>STEVE</CustomerName>
            <DedupeFound>YES</DedupeFound>
        </DedupeDetails>
    </Output>
</Response>

I started with something like this but not able to proceed further. I am trying to group ID parameters first, Inside that It start with primary customer Details. After Primary customer Details I have to iterate each customer ( Both Primary & secondary Here )

Any Suggestions / Corrections to make this achievable.

My XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="/">
        <Response>
     <xsl:for-each-group select="/Response/Output" group-by="ID">
      <xsl:sort select="ID"/>


    </xsl:for-each-group>
            
        </Response>
    </xsl:template>

</xsl:stylesheet>


Solution

  • I would take a different approach:

    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:key name="op" match="Output" use="ID"/>
    
    <xsl:template match="/Response">
        <xsl:copy>
            <xsl:for-each select="Output[CustomerType='PRIMARY']">
                <xsl:copy>
                    <xsl:copy-of select="ID|CustomerName|BranchName|SchemeName"/>
                    <xsl:for-each select="key('op', ID)">
                        <DedupeDetails>
                            <xsl:copy-of select="CustomerType|CustomerName|DedupeFound"/>
                        </DedupeDetails>
                    </xsl:for-each>
                </xsl:copy>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>
    

    Note that this assumes that each group has exactly one PRIMARY customer and zero or more SECONDARY customers. If the input always has one PRIMARY customer followed by one SECONDARY customer, as in your example, then this could be even simpler.