More Advanced XSLT Topics

XSL Templates

Often when performing an XSL transformation we want to transform all instances of a given tag in the input XML to a particular set of output tags. An efficient way of doing this is to define a template for each type of input tag - a set of processing instructions which defines how that input tag will be transformed.

Consider the XML below. This is a document describing web development languages in a generic XML format, which can then be transformed to a variety of output formats (e.g. XHTML, PDF, MS Word, etc) using different XSL stylesheets (one for each output format).

<?xml version='1.0'?>
<?xml-stylesheet type="text/xsl" href="document2.xsl"?>
<document>
<title>Web Development</title>
    <topic>
    <name>Server side languages</name>
        <heading>PHP</heading>
        <para>PHP is a server side language</para>
        <para>it was invented by Rasmus Lerdorf 
        and is open source</para>
        <heading>ASP</heading>
        <para>ASP is also a server side technology</para>
        <para>It was invented by Microsoft</para>
    </topic>
    <topic>
    <name>Client side languages</name>
        <heading>html</heading>
        <para>HTML is a markup language to describe the content  
        and structure of a web page.</para>
        <heading>JavaScript</heading>
        <para>JavaScript allows you to add interactivity 
        to web apps</para>
    </topic>
</document>
In the XSL to transform this to XHTML, we can write a template for each input tag, which defines how to convert that tag to output XHTML:
<xsl:template match="title">
    <h1> <xsl:value-of select="."/></h1>
</xsl:template>
<xsl:template match="topic/name">
    <h2> <xsl:value-of select="."/></h2>
</xsl:template>
This is saying that all <title> tags in the input XML will be converted to <h1> tags in the output XHTML, while all <name> tags within <topic> tags in the input XML will be converted to <h2> tags in the output XHTML. Note that the
<xsl:value-of select="."
means "insert whatever is inside the current tag". So the text inside the title tag in the input XML will be placed inside an h1 tag in the output XHTML.

Each template can be be called from the main XSLT document using the <xsl:apply-templates /> command. For example:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/document">
<html>
<head>
<title>
<xsl:value-of select="title"/>
</title>
</head>
<body>
<xsl:apply-templates /> 
</body>
</html>
</xsl:template>
<xsl:template match="title">
    <h1> <xsl:value-of select="."/></h1>
</xsl:template>
<xsl:template match="topic/name">
    <h2> <xsl:value-of select="."/></h2>
</xsl:template>
</xsl:stylesheet>
Note how the main block of code also has an <xsl:template> command - this is matching the whole input XML document (because the top level tag is <document> ). You have actually seen this in the other examples so far.

When we get to the <body>, however, we take a different approach to previous examples, which typically used a loop to loop through the input tags and converted them to output tags. In this example, the <xsl:apply-templates/> command is run. The result of this will be that the XSLT processor goes through the input XML, and each time it reaches a tag matching one of the templates, it applies the appropriate template matching the current input XML tag. The result of this will be that all <title> tags within the input XML will be converted to <h1> tags, while all <name> tags within <topic> tags will be converted to <h2> tags. This will work no matter how many <title> or <name> tags are in the input XML.

Exercise

Take the XSLT code above and add similar templates to transform all <para> tags within <topic> tags to <p>, and all <heading> tags within <topic> tags to <h3>.

Reading and writing tag attributes

Often our input XML will have attributes, e.g in the XML below, each text tag has a colour attribute:

<?xml version='1.0'?>
<?xml-stylesheet type='text/xsl' href='styles.xsl'?>
<data>
<student course="CNWD">George</student>
<student course="WDIT">Edward</student>
<student course="BIT">Harry</student>
<student course="SE">Craig</student>
</data>
How do we read in the attributes? This XSLT illustrates how:
<?xml version='1.0'?>
<xsl:stylesheet version='1.0'
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>styles</title>
<body>
<h1>Styles</h1>
<xsl:for-each select="/data/student">
<p>
    Name: 
    <xsl:value-of select="." />
    Course:    
    <xsl:value-of select="@course" />
</p>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

Notice how this code loops through each student tag in the input XML, and uses @course to select the course attribute from the student tag.

Generating attributes

Another thing we might want to do is generate attributes in the output from the XSLT. For instance, imagine we have this file:

<?xml version='1.0'?>
<?xml-stylesheet type='text/xsl' href='styles.xsl'?>
<data>
<text colour="red">George</text>
<text colour="yellow">Edward</text>
<text colour="blue">Harry</text>
<text colour="green">Craig</text>
</data>
and wish to generate HTML so that the text (George, Edward, Harry or Craig) is displayed in the specified colour. One way to do this in HTML is to use inline CSS, for example:
<p style="color: red">George</p>
So in the XSLT, we need to write out a paragraph tag, and somehow insert the style attribute so that the colour from the input XML is specified. The example below shows this:

<?xml version='1.0'?>
<xsl:stylesheet version='1.0'
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>styles</title>
<body>
<h1>Styles</h1>
<xsl:for-each select="/data/text">
<p>
    <xsl:attribute name="style">
    color:<xsl:value-of select="@colour" />
    </xsl:attribute>
    <xsl:value-of select="." />
</p>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

Notice how we're specifying the <p> tag and then attaching a style attribute to it with the xsl:attribute tag. We then dynamically generate the attribute's value (e.g. color:red) by inserting the colour attribute from the input XML.