XSLT v1.0::Grouping from Composite Values

When converting a XML, there are times that it is necessary to create a key against the data. These key is useful when inserting a new key value, in my case processing data transfer to DB.

Here is an example to create a key in that particular case:

<?xml version="1.0" encoding="UTF-8"?>
<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:strip-space elements="*"/>

<!--
In order to make unique key according to composite value [prefix + group_id],
so concatenate these values and define as a key as the following:
-->
<xsl:key name="newId" match="user" use="concat(field[@name='prefix']/text(), '_', field[@name='group_id']/text())"/>

<!--
Generate id from current value and compare the id with id generated from key use information of the first child from the result set.
If you want to verify the id values, add following:
<xsl:attribute name="u_id">
    <xsl:value-of select="generate-id(.)"/>
</xsl:attribute>
<key>
    <xsl:value-of select="generate-id(key('newId', concat(field[@name='prefix']/text(), '_', field[@name='group_id']/text())))"/>
</key>
-->

<xsl:template match="users">
    <users>
        <xsl:apply-templates select="user[generate-id() = generate-id(key('newId', concat(field[@name='prefix']/text(), '_', field[@name='group_id']/text()))[1])]" mode="group"/>
    </users>
</xsl:template>

<xsl:template match="user" mode="group">
    <user>
        <xsl:apply-templates select="field[@name='prefix'] | field[@name='user_id'] | field[@name='name'] | field[@name='address'] | field[@name='group_id']"/>
    </user>
</xsl:template>

<xsl:template match="field[@name='prefix'] | field[@name='user_id'] | field[@name='name'] | field[@name='address'] | field[@name='group_id']">
    <xsl:copy-of select=".">
        <xsl:apply-templates/>
    </xsl:copy-of>
</xsl:template>

</xsl:stylesheet>

Here’s a sample XML file to test the above.

<?xml version="1.0" encoding="UTF-8"?>
<users>
    <user uid="id3123397">
        <field name="prefix">001</field>
        <field name="user_id">temp1</field>
        <field name="name">Test User</field>
        <field name="address">300 Union Blvd.</field>
        <field name="city">Orange</field>
        <field name="group_id">1</field>
    </user>
    <user uid="id2040021">
        <field name="prefix">001</field>
        <field name="user_id">temp2</field>
        <field name="name">Test Man</field>
        <field name="address">123 Main St.</field>
        <field name="city">Apple</field>
        <field name="group_id">2</field>
    </user>
    <user uid="id3123397">
        <field name="prefix">001</field>
        <field name="user_id">temp3</field>
        <field name="name">Test Staff</field>
        <field name="address">100 Broadway</field>
        <field name="city">Orange</field>
        <field name="group_id">1</field>
    </user>
    <user uid="id3123333">
        <field name="prefix">002</field>
        <field name="user_id">temp4</field>
        <field name="name">Test Force</field>
        <field name="address">200 Park Ave.</field>
        <field name="city">Apple</field>
        <field name="group_id">2</field>
    </user>
</users>

This is the result XML.

<?xml version="1.0" encoding="UTF-8"?>
<users>
    <user uid="id2464385">
        <key>id2464385</key>
        <field name="prefix">001</field>
        <field name="user_id">temp1</field>
        <field name="name">Test User</field>
        <field name="address">300 Union Blvd.</field>
        <field name="group_id">1</field>
    </user>
    <user uid="id2464413">
        <key>id2464413</key>
        <field name="prefix">001</field>
        <field name="user_id">temp2</field>
        <field name="name">Test Man</field>
        <field name="address">123 Main St.</field>
        <field name="group_id">2</field>
    </user>
    <user uid="id2464509">
        <key>id2464509</key>
        <field name="prefix">002</field>
        <field name="user_id">temp4</field>
        <field name="name">Test Force</field>
        <field name="address">200 Park Ave.</field>
        <field name="group_id">2</field>
    </user>
</users>