AP.
AP.

Reputation: 5323

Create nested XML from flat XML using XSLT

I have a following XML file (that I do not control):

<recordset>
    <row>
      <field name="orderid">1</field>
      <field name="orderlineid">1</field>
      <field name="quantity">2</field>
      <field name="item">Thing 1</field>
    </row>
    <row>
      <field name="orderid">2</field>
      <field name="orderlineid">2</field>
      <field name="quantity">1</field>
      <field name="item">Thing 3</field>
    </row>
    <row>
      <field name="orderid">2</field>
      <field name="orderlineid">3</field>
      <field name="quantity">1</field>
      <field name="item">Thing 2</field>
    </row>
    <row>
      <field name="orderid">3</field>
      <field name="orderlineid">4</field>
      <field name="quantity">3</field>
      <field name="item">Other</field>
    </row>
</recordset>

And I am struggling with XSLT and for-each-group to group by order id and to generate a following XML:

<orders>   
   <order id="1" lines = "1">
        <orderline id = "1" quantity = "2" item = "Thing"> </orderline>
    </order>
    <order id="2" lines = "2">
        <orderline id = "2"  quantity = "1" item = "Thing 3"> </orderline>
        <orderline id = "3"  quantity = "1" item = "Thing 2"> </orderline>
    </order>
    <order id="3" lines="1">
        <orderline id = "4" quantity = "3" item = "Other"> </orderline>
    </order>
</orders>

Here is my attend so far:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:key name="keyOrder" match="row" use="field/@name = 'COMMANDE'" />
    <xsl:template match="resultset">
        <commandes xmlns:od="http://www.w3.org/2001/XMLSchema-instance">
            <xsl:apply-templates/>
        </commandes>
    </xsl:template>
    <xsl:template match="row">
        <orders>    
            <xsl:for-each-group select="./child::*" group-by="field/@name = 'orderid'">
                <order>
                    <xsl:value-of select="field[@name = 'COMMANDE']"/>
                </order>
            </xsl:for-each-group>
        </orders>
    </xsl:template> 
</xsl:stylesheet>

How can I :

Upvotes: 0

Views: 230

Answers (1)

Parfait
Parfait

Reputation: 107587

Consider the Muenchian Grouping which you begin with defining <xsl:key>:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:key name="keyOrder" match="row" use="field[@name='orderid']"/>

    <xsl:template match="recordset">
        <commandes xmlns:od="http://www.w3.org/2001/XMLSchema-instance">
            <xsl:apply-templates select="row[generate-id() =
                        generate-id(key('keyOrder', field[@name='orderid'])[1])]"/>
        </commandes>
    </xsl:template>

    <xsl:template match="row">
        <order id = "{field[@name='orderid']}" 
               lines = "{count(. | key('keyOrder', field[@name='orderid']))}"> 

                <xsl:for-each select="key('keyOrder', field[@name='orderid'])">
                    <orderline id = "{field[@name='orderlineid']}" 
                               quantity = "{field[@name='quantity']}"
                               item = "{field[@name='item']}" />
                </xsl:for-each>

        </order>
    </xsl:template> 

</xsl:stylesheet>

XSLT Fiddle Demo

Output

<?xml version="1.0" encoding="UTF-8"?>
<commandes xmlns:od="http://www.w3.org/2001/XMLSchema-instance">
   <order id="1" lines="1">
      <orderline id="1" quantity="2" item="Thing 1"/>
   </order>
   <order id="2" lines="2">
      <orderline id="2" quantity="1" item="Thing 3"/>
      <orderline id="3" quantity="1" item="Thing 2"/>
   </order>
   <order id="3" lines="1">
      <orderline id="4" quantity="3" item="Other"/>
   </order>
</commandes>

Upvotes: 1

Related Questions