Search code examples
xmlxslt-1.0xslt-grouping

Grouping XML multiple elements into a single one


This is my XML file for which we have write an xsl file. Purpose for this xsl is to use for XML operation.

Input XML

<ns1:POOrder xmlns:ns1="http://tanole/SO11/ERP_PD_EMS/RD_SalesOrder_Defirm">
    <RIOrder>
        <Order>
           <SerialNo>0922830281</SerialNo>
            <ItemID>2345</ItemID>
            <OrderNo>0128333331</OrderNo>
        </Order>
        <Order>
            <SerialNo>0922830281</SerialNo>
            <ItemID>2345</ItemID>
            <OrderNo>0128333331</OrderNo>
        </Order>
    </RIOrder>
</ns1:POOrder>

Expected Output:

<RIOrders>
  <R1 OrderNo="0128333331" ItemID="2345"  SerialNo="0922830281"/>
</RIOrders>

I am trying to implement this logic in my xsl file, but unable to get so.This is what I am currently trying to do, I have tried a few things and cannot figure out a way to do what I need.

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" indent="yes" />
    <xsl:key name="orders" match="Order" use="OrderNo" />
    <xsl:template match="/*">
        <RIOrders>
            <xsl:for-each select="RIOrder/Order[generate-id() = generate-id(key('orders', OrderNo)[1])]">
                <xsl:apply-templates select="key('orders', OrderNo)" />
            </xsl:for-each>
        </RIOrders>
    </xsl:template>
    <xsl:template match="Order">
        <R1 OrderNo="{OrderNo}" ItemID="{ItemID}" SerialNo="{SerialNo}" UpdateDateOn="N" />
    </xsl:template>
</xsl:stylesheet>

Any help would be appreciated.


Solution

  • If you don't want duplicate <Order> elements in the output, don't apply templates to the group members, but to the group.

    You currently do "for each group, apply templates to all elements of the group":

    <xsl:for-each select="RIOrder/Order[generate-id() = generate-id(key('orders', OrderNo)[1])]">
        <xsl:apply-templates select="key('orders', OrderNo)" />
    </xsl:for-each>
    

    whereas you actually want to do:

    <xsl:apply-templates select="RIOrder/Order[generate-id() = generate-id(key('orders', OrderNo)[1])]" />
    

    Output for your sample input is:

    <RIOrders>
       <R1 OrderNo="0128333331" ItemID="2345" SerialNo="0922830281" UpdateDateOn="N" />
    </RIOrders>