« March 7, 2008 | Main | April 10, 2008 »

April 8, 2008 Archives

April 8, 2008

Pairing Off in XSLT

Pairing Off in XSLT

My friend Newton was just fighting to transform some XML that was structured in a awkward way.  The machine generated XML he was working with basically paired off successive elements, for example to provide a credential prompt and then the following element contained the credential itself.  It took a bit of fiddling to get the right XPath expression to perform the transformation.  I thought it would be illuminating to share it with you and hopefully someone will find a better solution than the one we came up with.

The Source

The source XML looked like this
<?xml version="1.0" encoding="UTF-8" ?>
<exampleElement>

    <AttributeElement>
        <DisplayElement>
            <SelectElement attribute1="A"/>
        </DisplayElement>
    </AttributeElement>

    <AttributeElement>
        <DisplayElement>
            <PasswordElement attribute1="1"/>
        </DisplayElement>
    </AttributeElement>
...
    <AttributeElement>
        <DisplayElement>
            <SelectElement attribute1="E"/>
        </DisplayElement>
    </AttributeElement>

    <AttributeElement>
        <DisplayElement>
            <PasswordElement attribute1="5"/>
        </DisplayElement>
    </AttributeElement>

</exampleElement>
Note the pairing of the Attribute elements.

The Target

The target XML looked like this
<?xml version = '1.0' encoding = 'UTF-8'?>
<exampleElement>

     <Attribute>
          <Select attribute1="A"/>
          <Password attribute1="1"/>
     </Attribute>
...
     <Attribute>
          <Select attribute1="E"/>
          <Password attribute1="5"/>
     </Attribute>
</exampleElement>

The Problem

The challenge was after identifying a path with a SelectElement element how to select the following path that had a PasswordElement element.

The Answer is Axis

The trouble with XSLT is that I don't do enough of it to remember all the tools available.  In this case it was very simple once I had remembered how axis work.  Here is my solution
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <exampleElement>
            <xsl:for-each select="/exampleElement/AttributeElement/DisplayElement/SelectElement">
                <Attribute>
                    <Select>
                        <xsl:attribute name="attribute1"><xsl:value-of select="@attribute1"/></xsl:attribute>
                    </Select>
                    <Password>
                        <xsl:attribute name="attribute1">
                    <xsl:value-of select="following::AttributeElement[1]/DisplayElement/PasswordElement/@attribute1"/>
            </xsl:attribute>
                    </Password>
                </Attribute>
            </xsl:for-each>
        </exampleElement>
    </xsl:template>
</xsl:stylesheet>
This solution iterates over all the SelectElement elements and then for each of those elements it picks out the following PasswordElement in the document.  It does this by using the XPath expression "following::AttributeElement[1]/DisplayElement/PasswordElement/@attribute1".
The "following::" axis selects all nodes in the document that come after the given SelectElement element.  This flattens the hierarchy enabling us to choose the next AttributeElement element by selecting the AtrributeElement element with index 1 (AttributeElement[1]).  We can then traverse that part of the XML using the normal child axis.  Simple when its done but when you rarely use axis other than the child axis it takes a while to remember how they work.

Reference

I find the two O'Reilly books on XSLT to be very helpful when struggling with XPath and XSLT.  These are the Doug Tidwell XSLT book and the Sal Mangano XSLT Cookbook.

I hope this saves sombody some time.

About April 2008

This page contains all entries posted to Antony Reynolds' Blog in April 2008. They are listed from oldest to newest.

March 7, 2008 is the previous archive.

April 10, 2008 is the next archive.

Many more can be found on the main index page or by looking through the archives.

Powered by
Movable Type and Oracle