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>

Google Maps:: So easy, you can do it within a second

Let’s get down on it!

First off, the basic setup:

<script type="text/JavaScript" src="http://maps.google.com/maps/apis/js?sensor=false" />

By doing this you added the reference to Google Maps API in your webpage. Only thing you remember when referencing to Google Maps are setting the sensor parameter.
sensor = true/false – this will tell Google Maps API whether you are using GPS sensor or not. Now, let’s create a canvas.

<div id="map" />

Then, use style to adjust the size of the canvas.

#map {
    height: 400px;
    width: 450px;
}

Then put them into the jQuery document.ready event to let your browser grab the map object.

$(document).ready(function() {
    var tLatlng = new google.maps.LatLng(32.842671, 6.503906);
    var myOptions = {
        center:latlng,
        zoom:10,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        disableAutoPan: false,
        navigationControl: true,
        navigationControlOptions: { style:google.maps.NavigationControlStyle.SMALL },
        mapTypeControl: true,
        mapTypeControlOptions: { style:google.maps.MapTypeControlStyle.DROPDOWN_MENU }
    };
    var map = new google.maps.Map(document.getElementById("map"), myOptions );
    var marker= new google.maps.Marker({
        position: new google.maps.LatLng(9.931544168615512,76.27632894178791),
        title: "My Marker",
        clickable: true,
        map: map
    });
    var infoWindow = new google.maps.InfoWindow({
        content: "I am here!"
    });

    // now we attach events 
    google.maps.event.addListener(marker, "mouseover", function(){
        infoWindow.open(map,marker);
    });
    google.maps.event.addListener(marker, "mouseout", function(){
        infoWindow.close(map,marker);
    });
});

That’s about it. It is true that most people think Google Maps is so easy. But is it? Let me give you an example. How would you create a certain line like the one in this example?

http://code.google.com/apis/maps/documentation/javascript/examples/layer-kml.html

XSLT::Field mapping through an additional XML

Sometime we need to introduce a way to create an association in the process. In doing so, introducing a map file provides a simple way to do such.
Here’s an example:

I add a mapper.xml that holds two mapping categories (grup id and user type).

<!-- // mapper.xml // -->
<?xml version="1.0" encoding="UTF-8"?>
<mapper>
    <group_id>
        <value id="1">2</value>
        <value id="2">3</value>
    </group_id>
    <user_type>
        <value type="Test User">Real User</value>
        <value type="Public">Private</value>
    </user_type>
</mapper>

Here’s an example file.

<?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="*"/>

<!-- declare XSL variables -->
<xsl:variable name="groupId" select="document('mapper.xml')/mapper/group_id"/>
<xsl:variable name="userType" select="document('mapper.xml')/mapper/user_type"/>

<xsl:template match="field">
    <xsl:choose>
        <xsl:when test="@name='gid'">
            <xsl:call-template name="getGrpId">
                <xsl:with-param name="gid" select="."/>
            </xsl:call-template>
        </xsl:when>
        <xsl:when test="@name='usertype'">
	    <!-- if usertype tag get the value and get the mapping value -->
            <xsl:call-template name="getUserType">
                <xsl:with-param name="utype" select="."/>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:copy-of select="."/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>
<xsl:template name="getGrpId">
    <xsl:param name="gid"/>
    <field name="gid">
	<!-- You can simply refer the mapper by variable and compare to get the results -->
        <xsl:value-of select="$groupId/value[@id=$gid]"/>
    </field>
</xsl:template>

<xsl:template name="getUserType">
    <xsl:param name="utype"/>
    <field name="usertype">
        <xsl:value-of select="$userType/value[@type=$utype]"/>
    </field>
</xsl:template>

XSLT::Template example

<?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:template match="/">
    <users>
    <xsl:for-each select="users/user">
        <user><xsl:apply-templates /></user>
    </xsl:for-each>
    </users>
</xsl:template>

<xsl:template match="field">
    <xsl:choose>
        <xsl:when test="@name='name'">
            <xsl:call-template name="getname">
                <xsl:with-param name="fname" select="." />
                <xsl:with-param name="lname" select="following-sibling::field[position()=1]" />
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:copy-of select="." />
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template name="getname">
    <xsl:param name="fname" />
    <xsl:param name="lname" />
    <xsl:if test="string-length($lname) > 0">
        <field name="name">
            <xsl:value-of select="concat($fname, ' ', $lname)"/>
        </field>
    </xsl:if>
    <xsl:if test="string-length($lname) = 0">
        <field name="name">
            <xsl:value-of select="$fname"/>
        </field>
    </xsl:if>
</xsl:template>

</xsl:stylesheet>