An Extensible Stylesheet Language (XSL) Tutorial

This tutorial covers the basics of XSL. Before reading this
tutorial you should already be familiar with XML. You may want to read my XML
tutorial. Click the above link to do so.

What is XSL?

XSL stands for Extensible
Stylesheet Language.

XSL is similar to Cascading Style Sheet (CSS)
language in that it lets you format the display of XML data. This, however, is
were the similarities stop. To view an XML file with and without CSS
click here.

With CSS, the structure of the XML data must be identical to the structure
of its display. CSS associates formatting properties with XML tags and is said
to "decorate the XML tree". Thus, forethought must be used when
designing XML data so you can display it properly. This violates XML's goal of
separation of data.

XSL lets you transform the XML tree
into a new tree without changing the XML source data. Then, the XML can be
displayed differently just by switching style sheets.

However, discussions contained herein focus on Microsoft's implementation of
XSL. All samples require their Internet Explorer, version 5.0 or later, browser
which includes their Msxml parser. All references to the Msxml parser, assume
Msxml V2.5 or later. For more information or to download Microsoft's XML
products, visit their site.

XSL as a Programming Language

Since XSL is a language, it enables you to use conditional formatting and
looping constructs, apply selection criteria, sort and filter the XML data, and
transform the XML tree structure. Unlike CSS, you can also describe irregular,
non-repetative data.

Creating and Filling an HTML Template

With XSL you can combine XML data with an HTML template for display purposes.
The following XML data is repetitive -- the stock element is repeated
several times with the same subelements.

The <xsl:for-each> element
locates a set of elements in the XML data ("stock" elements inside the
"portfolio" element) and repeats a portion of the template for each one. This
sample contains three stock elements so three rows will be created in the
table.

The Select attribute tells how to find a set of
elements. The syntax for this attribute is called an XSL
pattern. Patterns work like navigating a file system tree where a
slash (/) selects subdirectories relative to the current directory.

In an XSL style sheet, navigation starts at the current node and drills down
into the XML data hierarchy, selecting all nodes matching the pattern. Here,
the pattern portfolio/stock starts at the root and drills down through
the "portfolio" element to select the three "stock" children.

XSL patterns can be complex and are described in more detail later.

Within the <xsl:for-each> element, you can further drill down to
select children of each "stock" element. The <xsl:value-of>
element selects a specific child then inserts that child's text into the
template. The patterns inside the <xsl:value-of> element's select
attribute do not start at the root. They are relative to the element selected
in the <xsl:for-each> element.

Because XSL style sheets are XML files, they begin with an XML declaration.
Also, both they and the HTML template must be well
formed.

The <xsl:stylesheet> element denotes this is
a style sheet file and specifies an XSL namespace URL. The <xsl:template
match="/"> statement indicates the template corresponds to the
root (/) of the XML source document.

In the XML file, a processing instruction was added
so the parser knows to use the XSL style sheet.

The name attribute specifies the name of the attribute that will be added
to the output. Its value is determined by evaluating its tag.

In this example, a title attribute is added to the <TR> element to
display a ToolTip. The ToolTip's text is created by mixing text with element
and attribute values from the source XML document.

Attributes can be added to elements that already have attributes specified on
them in the XML source. However, you can't add an attribute to an element that
already has an attribute with the same name. Also, attributes added with
<xsl:attribute> must appear before children are added to the element.

Sorting

The <xsl:for-each> element displays repetitive data in the order it
appears in the XML document. The order-by attribute
lets you to sort the data within a specified node, price
in the this case.

<xsl:for-each select="portfolio/stock" order-by="price">

A minus sign (-) preceding a sort key causes the sort to occur in descending
order. A plus sign (+), which is implied, can optionally be used to explicitly
indicate an ascending sort.

You can sort by multiple keys. Just separate them with semicolons. If multiple
stocks have the same price, they will then be sorted by name. Notice
that the price data is first converted to a numeric data type to insure proper
sorting.

order-by="- number(PRICE); NAME"

Conditional Logic

Conditional logic in XSL lets you display XML data in your HTML based on certain
conditions being met in the XML source. Conditional templates are defined using
the <xsl:if> and <xsl:choose>
elements.

If Logic
The XML data in sample 1 above has an "exchange" attribute associated with the
"stock" element. Suppose you want to output an asterisk "*" when the exchange
is "nasdaq". This can easily be done using the <xsl:if>
element after the select="symbol" line of XSL Sample 1.

Instead of displaying text, an asterisk in this case, we could have displayed
elements and attributes as well.

The test attribute uses a pattern. If the query associated with
the pattern selects one or more nodes, the <xsl:if> template is inserted.
The above query looks to see if the stock element has an "exchange" attribute.
Then it checks if the exchange attribute's value equals "nasdaq".

Here's what happens. When the page is completely loaded, including the data
islands, its onload event fires and calls the transformNode method
on the XML source data.

TransformNode takes the DOM node representing the XSL style sheet as a
parameter. The result is XML text. Since the menuxsl.xsl style sheet produces
well-formed HTML, its output can be fed into the xslTarget DIV element
for display using the innerHTML property.

Note that the XMLDocument property is used on the "style" data island.
Without this, the ID of the data island is thought to be an HTML element, in
this case the <XML> element.

We could have just used XMLDocument instead of style.XMLDocument. However,
specifying the full name makes it clear that we are operating on the contents
of the data island and not the <XML> element representing the data
island.

What happens if nothing happens?

Errors can occur during the parsing of the XML and XSL documents and during the
transformation. It is possible to trap and display these errors. This is
explained in detail in the XML Software Development Kit available on
their site.

XSL Patterns

XSL Patterns provide a query language for
identifying nodes in an XML document. Nodes can be identified by their type,
name, value, and relationship to other nodes in the document. A pattern
describes a path through the XML hierarchy with a slash-separated list
of child element names.

The following query finds 'author' elements with a 'period' attribute whose
value is 'classical' and that are contained in the 'authors' element at the
document root.

"/authors/author[@period='classical']".

XML documents represent a hierarchy of nodes, similar to the hierarchy of
folders and files in a file system. Here are some similarities between the two.

File System

XSL Patterns

Hierarchy of folders and files

Hierarchy of elements and other nodes in an XML document

Files at each level have unique names

Element names at each level might not be unique. XSL Patterns identify all the
matching elements

URLs are evaluated relative to the "current folder"

XSL Patterns are evaluated relative to a particular node called the
context for the query.

Let's use this XML data and illustrate some of the basic queries using XSL
Patterns.

XSL Patterns can use any node in the XML document as the
context (starting point) for a query. In an XSL style sheet, the
context for a query is the source node being currently processed by an <xsl:template>
or <xsl:for-each> element.

The following pattern starts from the XML document's root and traverses down the
hierarchy to the "name" elements. It identifies all elements that match
the path.

authors/author/name

Patterns can also use wildcards. Here, we can find
any name element regardless of whether it is a child of the author
element. We can also find both name and nationality elements
under author elements.

authors/*/name
authors/author/*

We can specify branches on the path by using square
brackets. The branch on the author element indicates only author elements
with nationality children should be considered. In the second statement,
only the names of Russian authors are returned.