An XSLT Stylesheet

Contact Us or call 1-877-932-8228
An XSLT Stylesheet

An XSLT Stylesheet

Let's start by looking at a simple XML document and an XSLT stylesheet which is used to transform the XML to HTML.

Code Sample:

XsltBasics/Demos/Paul.xml
<?xml version="1.0"?>
<?xml-stylesheet href="beatle.xsl" type="text/xsl"?>
<person>
	<name>
		<firstname>Paul</firstname>
		<lastname>McCartney</lastname>
	</name>
	<job>Singer</job>
	<gender>Male</gender>
</person>

This is a straightforward XML document. The processing instruction at the top indicates that the XML document should be transformed using Beatle.xsl (shown below).

Code Sample:

XsltBasics/Demos/Beatle.xsl
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="child::person">
	<html>
		<head>
			<title>
				<xsl:value-of select="descendant::firstname" />
				<xsl:text> </xsl:text>
				<xsl:value-of select="descendant::lastname" />
			</title>
		</head>
		<body>
			<xsl:value-of select="descendant::firstname" />
			<xsl:text> </xsl:text>
			<xsl:value-of select="descendant::lastname" />
		</body>
	</html>
</xsl:template>
</xsl:stylesheet>

Note that the document begins with an XML declaration. This is because XSLTs are XML documents themselves. As with all XML documents, the XML declaration is optional.

The second line (shown below) is the document element of the XSLT. It states that this document is a version 1.0 XSLT document.

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

The third line (shown below) indicates that the resulting output will be HTML.

<xsl:output method="html"/>

The fourth line is an open <xsl:template> element. The match attribute of this tag takes an XPath, which indicates that this template applies to the person node of the XML document. Because person is the document element of the source document, this template will only run once.

There are then a few lines of HTML tags followed by two <xsl:value-of /> elements separated by one <xsl:text> element. The <xsl:value-of /> tag has a select attribute, which takes an XPath pointing to a specific element or group of elements within the XML document. In this case, the two <xsl:value-of /> tags point to firstname and lastname elements, indicating that they should be output in the title of the HTML page. The <xsl:text> element is used to create a space between the first name and the last name elements.

<xsl:value-of select="descendant::firstname" />
<xsl:text> </xsl:text>
<xsl:value-of select="descendant::lastname" />

There are then some more HTML tags followed by the same XSLT tags, re-outputting the first and last name of the Beatle in the body of the HTML page.

xsl:template

The xsl:template tag is used to tell the XSLT processor what to do when it comes across a matching node. Matches are determined by the XPath expression in the match attribute of the xsl:template tag.

Code Sample:

XsltBasics/Demos/FirstName.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
				xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:output method="text"/>
	<xsl:template match="firstname">
		We found a first name! 
	</xsl:template>
</xsl:stylesheet>

If we use this XSLT to transform XsltBasics/Demos/FirstName.xml, which has the same XML as XsltBasics/Demos/Paul.xml , the result will be:

	We found a first name!
McCartneySingerMale

The text "We found a first name!" shows up only once, because only one match is found. The text "McCartneySingerMale" shows up because the XSLT engine will continue looking through an XML document until it is explicitly told to stop. When it reaches a text node with no matching template, it uses the default template, which simply outputs the text. "McCartney", "Singer" and "Male" are the text node values inside the elements that follow the FirstName element.

Let's see what happens if we transform an XML document with multiple FirstName elements against this same XSLT. Take, for example, the XML document below.

Code Sample:

XsltBasics/Demos/Beatles.xml
<?xml version="1.0"?>
<?xml-stylesheet href="FirstName.xsl" type="text/xsl"?>
<beatles>
	<beatle link="http://www.paulmccartney.com">
		<name>
			<firstname>Paul</firstname>
			<lastname>McCartney</lastname>
		</name>
	</beatle>
	<beatle link="http://www.johnlennon.com">
		<name>
			<firstname>John</firstname>
			<lastname>Lennon</lastname>
		</name>
	</beatle>
	<beatle link="http://www.georgeharrison.com">
		<name>
			<firstname>George</firstname>
			<lastname>Harrison</lastname>
		</name>
	</beatle>
	<beatle link="http://www.ringostarr.com">
		<name>
			<firstname>Ringo</firstname>
			<lastname>Starr</lastname>
		</name>
	</beatle>
	<beatle link="http://www.webucator.com" real="no">
		<name>
			<firstname>Nat</firstname>
			<lastname>Dunn</lastname>
		</name>
	</beatle>
</beatles>

The resulting output will be as follows.

	We found a first name!
McCartney
	We found a first name!
Lennon
	We found a first name!
Harrison
	We found a first name!
Starr
	We found a first name!
Dunn

Each time a firstname element is found in the source XML document, the text "We found a first name!" is output. For the other elements with text (in this case, only lastname elements), the actual text is output.

xsl:value-of

The xsl:value-of element is used to output the text value of a node. To illustrate, let's look at the following example.

Code Sample:

XsltBasics/Demos/ValueOf1.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
				xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:output method="text"/>
	<xsl:template match="firstname">
		We found a first name and it's <xsl:value-of select="."/>
	</xsl:template>
</xsl:stylesheet>

If we use this XSLT to transform XsltBasics/Demos/Beatles-VO1.xml, which has the same XML as XsltBasics/Demos/Beatles.xml , the result will be:

 We found a first name and it's PaulMcCartney
 We found a first name and it's JohnLennon
 We found a first name and it's GeorgeHarrison
 We found a first name and it's RingoStarr
 We found a first name and it's NatDunn

The select attribute takes an XPath, which is used to indicate which node's value to output. A single dot (.) refers to the current node (i.e, the node that was matched by the template).

Don't let the last names at the end of each line confuse you. These are not part of the output of the xsl:value-of element. They are there as a result of the default template, which outputs the text value of the element found.

To illustrate this, let's look at another example.

Code Sample:

XsltBasics/Demos/ValueOf2.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
				xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:output method="text"/>
	<xsl:template match="firstname">
		We found a first name and it's <xsl:value-of select="."/>
	</xsl:template>
	<xsl:template match="lastname">
		We found a last name and it's <xsl:value-of select="."/>
	</xsl:template>
</xsl:stylesheet>

If we use this XSLT to transform XsltBasics/Demos/Beatles-VO2.xml, which has the same XML as XsltBasics/Demos/Beatles.xml , the result will be:

	We found a first name and it's Paul
	We found a last name and it's McCartney
	We found a first name and it's John
	We found a last name and it's Lennon
	We found a first name and it's George
	We found a last name and it's Harrison
	We found a first name and it's Ringo
	We found a last name and it's Starr
	We found a first name and it's Nat
	We found a last name and it's Dunn

This XSLT has a template for both firstname and lastname and so it never uses the default template.

Whitespace and xsl:text

Whitespace in an XSLT template is output literally. If you're not careful, this can lead to undesirable results. To illustrate, let's look at the following XML and XSLT documents.

Code Sample:

XsltBasics/Demos/WhiteSpace1.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="WhiteSpace1.xsl"?>
<example>
	<blurb>
		Hello World!
	</blurb>
</example>

Code Sample:

XsltBasics/Demos/WhiteSpace1.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
				xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:output method="text"/>
	<xsl:template match="blurb">
		Literal			Text
	</xsl:template>
</xsl:stylesheet>

When XsltBasics/Demos/WhiteSpace1.xml is transformed against XsltBasics/Demos/WhiteSpace1.xsl, the output looks like this:

There is an empty line before and after the text. There are also two tabs preceding the text. This is because the whitespace between <xsl:template match="blurb"> and Literal Text and the whitespace between Literal Text and </xsl:template> is output literally.

If you did not want that extra whitespace to show up in the output, you could use the following XSLT instead.

Code Sample:

XsltBasics/Demos/WhiteSpace2.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
				xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:output method="text"/>
	<xsl:template match="blurb">
		<xsl:text>Literal			Text</xsl:text>
	</xsl:template>
</xsl:stylesheet>

When XsltBasics/Demos/WhiteSpace2.xml, which has the same XML as XsltBasics/Demos/WhiteSpace1.xml , is transformed against XsltBasics/Demos/WhiteSpace2.xsl, the output looks like this:

Because whitespace between open tags (e.g, between <xsl:template match="blurb"> and <xsl:text>) and whitespace between close tags (e.g, </xsl:text> and </xsl:template>) is ignored, the only content that is output is the text between the open and close xsl:text tags.

Inserting Whitespace with xsl:text

The examples above illustrate how xsl:text can be used to remove whitespace. It can also be used to add whitespace where there otherwise wouldn't be any. Let's take a look at another example.

Code Sample:

XsltBasics/Demos/WhiteSpace3.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
				xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:output method="text"/>
	<xsl:template match="name">
		<xsl:value-of select="firstname"/>
		<xsl:value-of select="lastname"/>
	</xsl:template>
</xsl:stylesheet>

When XsltBasics/Demos/Beatles-WS3.xml, which has the same XML as XsltBasics/Demos/Beatles.xml , is transformed against XsltBasics/Demos/WhiteSpace3.xsl, the output looks like this:

Clearly, this isn't the desired output. We'd like to have each Beatle on a separate line and spaces between their first and last names like this:

However, because whitespace between two open tags and between two close tags is ignored, we don't get any whitespace in the output. We can use xsl:text to fix this by explicitly indicating how much whitespace we want in each location.

Code Sample:

XsltBasics/Demos/WhiteSpace4.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
				xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:output method="text"/>
	<xsl:template match="name">
		<xsl:value-of select="firstname"/>
		<xsl:text> </xsl:text>
		<xsl:value-of select="lastname"/>
		<xsl:text>
</xsl:text>
	</xsl:template>
</xsl:stylesheet>

Notice that the second close xsl:text hugs the left border. If we were to put any space before it on that line, that space would show up in the output. To see the desired result, transform XsltBasics/Demos/Beatles-WS4.xml against XsltBasics/Demos/WhiteSpace4.xsl.

Next