[ Prev ] [ Index ] [ Next ]

xslt

Created Tuesday 28/7/2009

XSLT is a xml transformation using stylesheet. The indeded purpose is to stream over xml in order to produce either a different xml structure or a differnent output representation (like xhtml, plain text and similar). There are many xslt engines.

All of the examples in this doclet use the following xml as input structure:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<someroot somerootattribute="foo">
    <Foo type="1">
        <Foobar>P52483</Foobar>
        <Foobar>P52483</Foobar>
        <Bar>
            <Barvalue datatype="varchar">Bar1</Barvalue>
            <Barvalue datatype="varchar">Bar2</Barvalue>
            <Barvalue datatype="int">200</Barvalue>
            <Barvalue datatype="double">1.23</Barvalue>
        </Bar>
    </Foo>
    <Foo/>
    <Foo type="2">
        <Foobar>A34</Foobar>
        <Foobar>B65</Foobar>
        <Bar>
            <Barvalue datatype="double">2.32</Barvalue>
        </Bar>
    </Foo>
    <Zorp>
        <Foobar>under zorp</Foobar>
        <froz>A froz</froz>
    </Zorp>
</someroot>

1. Starting the transform

The simplest way to get the transform processs started is to use a xsl:template match on the root path (which can be matched by /). For example, a stylesheet transform for the example xml above, matching / and applying a template selection for all //Foo, to select only the Fobar elements:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<!-- match the root path -->
<xsl:template match="/">
    <FooList>
        <xsl:apply-templates select="//Foo"/>
    </FooList>
</xsl:template>

<xsl:template match="Foo">
	<Foobar>
    		<xsl:value-of select="Foobar"/>
	</Foobar>
</xsl:template>

</xsl:stylesheet>

Produces:

<?xml version="1.0" encoding="utf-8"?>
<FooList>
	<Foobar>P52483</Foobar>
	<Foobar/>
	<Foobar>A34</Foobar>
</FooList>

2. Template matching

image Tip: Eliminate unwanted child nodes with a matching template of <xsl:template match="text()|@*"/>

Template matching is event driven matching of nodes in the document be tranformed. Compare this to template calls, which are a procedural style of invoking a template. Invoking xsl:apply-templates, applies a template to the current element or to the current element's child nodes against all matching elements. Adding a select attribute to the xsl:apply-templates causes the function to only process child element matching the value of the attribute. It is possible to use the select attribute to specify the processing order of child nodes.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="/">
        <FooList>
            <xsl:apply-templates/>
        </FooList>
    </xsl:template>
    
    <xsl:template match="Foo">
        <Foobar>
            <xsl:value-of select="Foobar"/>
        </Foobar>
    </xsl:template>

    <!-- eliminate all other nodes (i.e. anything node that is not a Foo) -->
    <xsl:template match="text()|@*"/>

</xsl:stylesheet>

Produces:

<?xml version="1.0" encoding="utf-8"?>
<FooList>
    <Foobar>P52483</Foobar>
    <Foobar/>
    <Foobar>A34</Foobar>
    <Bar>A froz</Bar>
</FooList>

3. Template calls

image Todo: Change example to be a parameterized call example

Templates can be called as opposed to matched. The xsl:call-template element is used to invoke a template. Like, apply-templates, the the xsl:call-template can be parameterised.

4. Preserving markup tags

In certain cases all that may be required is to produce the same xml but with perhaps a few extra tags (perhaps some meta tag information or perhaps to wrap certain tag elements in specicif tags). The xsl:copy-of function provides this behaviour. In the following example, tags tree's from the input xml are written to output xml but with different parent nodes.

The following xslt snipet will wrap the Foo elements in FooTag tags and dump the lot under a new tag tree called FooList:

<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

	<xsl:template match="/">
		<FooList>
			<xsl:apply-templates select="//Foo"/>
		</FooList>
	</xsl:template>
	
	<xsl:template match="Foo">
		<FooTag>
			<xsl:copy-of select="Foobar"/>
		</FooTag>
	</xsl:template>
	
</xsl:transform>

Produces:

<?xml version="1.0" encoding="utf-8"?>
<FooList>
	<FooTag>
		<Foobar>P52483</Foobar>
		<Foobar>P52483</Foobar>
	</FooTag>
	<FooTag/>
	<FooTag>
		<Foobar>A34</Foobar>
		<Foobar>B65</Foobar>
	</FooTag>
</FooList>

5. Invoking java

Call outs to java whilst executing an xsl transform are done with the <xsl:java> tag. The java namespace must be added to the xsl:stylesheet> attributes (or to the <xsl:transform> attributes if the xslt is xsl:transform instead). E.g., for xsl:stylesheet specify xmlns:java namespace, as in:

<xsl:stylesheet version="1.0"
    exclude-result-prefixes="java"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:java="http://xml.apache.org/xalan/java"

The following snipet performs a callout to a static method called Foo.doFoo on all the Foobar tag elements:

<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

	<xsl:template match="/">
		<FooList>
			<xsl:apply-templates select="//Foo"/>
		</FooList>
	</xsl:template>
	
	<xsl:template match="Foo">
		<Foo>
			<xsl:value-of select="java:au.com.foo.Foo.doFoo(Foobar)"/>
		</Foo>
	</xsl:template>
	
</xsl:transform>

6. Conditional logic

The xsl:if and xsl:when functions provide support for performing different transformation based on some condition. Both functions require the test operand, which takes a string argument naming the function to use in testing. Tag values or variables can be used in the test. The following outputs a concatenation of Foobar elements, separated by semi-colon. This contrivance uses xsl:when to determine if we dealing with the first match to avoid outputting a leading semi:

<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <FooList>
            <xsl:apply-templates select="//Foo"/>
        </FooList>
    </xsl:template>
    <xsl:template match="Foo">
        <FoobarList>
            <xsl:for-each select="Foobar">
                <xsl:call-template name="FoobarTemplate">
                    <xsl:with-param name="index" select="position()"/>
                </xsl:call-template>
            </xsl:for-each>
        </FoobarList>
    </xsl:template>
    <xsl:template name="FoobarTemplate">
        <xsl:param name="index"/>
        <xsl:choose>
            <xsl:when test="$index='1'">
                <xsl:value-of select="normalize-space(.)"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="concat(';', normalize-space(.))"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:transform>

The above produces the following when run over the example xml:

<FooList>
    <FoobarList>P52483;P52483</FoobarList>
    <FoobarList/>
    <FoobarList>A34;B65</FoobarList>
</FooList>

7. Output format

The default output format for transformation is xml. Alterante output formats can be generated using the xsl:output function. The following is an explicit declaration, specifying xml indented output:

<xsl:output method="xml" indent="yes"/>

8. Command line execution

There are several tools for transforming and xml document using xslt, examples are saxon and xalan-j. Using saxon, or example, a transformation of foo.xml using foo.xslt with the transformed document written to foo-transformed.xml can be achieved with:

bash $ saxon -o foo-transformed.xml foo.xml foo.xslt

9. EditiX

EditiX (www.editix.com) is opensource tool for xsd, xslt, xml manipulation. Runs transformation over xml using xslt, with debug/breakpoint support. Built in xml parser (SAX) and Tranformation engine (x) but has support for plugging in others (if required). The application is written in java, so installation is pretty straight forward. EditiX can be downloaded from here.

9.A Running a tranformation

open an xslt document and select the 'Transform a document with this xslt...' menu item from within 'XSLT/XQuery' menu on the menu bar. Choose an xml document to transform on the opened XSLT Parameters dialog ('XML Document source (*.xml)' field). Specify a result document pathname (html is good choice if choosing 'Edit' as the result document processing, otherwise specify an xml output pathname If 'No operation' is selected). Can set break points if required prior to execution. REsulting transformed doco can be spit out as xml or html and will open in a new tab. The pretty printer is usefule for checking the results ('Format' menu item from 'XML' menu item on menu bar)

9.B Generating documentation

EditX can generate documentation from an from xsd. To do this, open an xsd and then choose the Generate a documentation from this schema menu item from within the DTD/Schema menu item on the menu bar. The documentation generator will produce serveral files (html and some images), so it's a good idea to wite the generated doco to it's down directory.

10. Template matching from a dynamic path selection

image Note: This solution uses saxon (xslt parser extensions). Be sure to declare the name space for saxon as http://saxon.sf.net

XSLT (1.0) does not support dynamic path selection. E.g., it is not possible to do something like <xsl:apply-templates match"foobar" select="$somevar"/> (where perhaps somevar is '/foo/bar'. A solution to this is to use an xslt parser extension like saxon:evaluate. E.g.,

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:saxon="http://saxon.sf.net/">

<xsl:variable name="somevar" value="/foo/bar"/>
<xsl:apply-templates select="saxon:evaluate($somevar)"/>

Stuart Moorfoot © 29 July 2009 foo@bund.com.au


No backlinks to this page.