Much of XSLT’s functionality is exercised in the form of elements that perform functions and tasks. In fact, the whole language is XML-based and describing its features is already the subject of several books. This section presents some of the XSLT elements and fundamentals so you can begin using it in your daily work.
The xsl:stylesheet
element is always the root element of standalone stylesheets, and is
also used for embedded stylesheets. The stylesheet
element contains some optional
and mandatory attributes that provide more details about the
stylesheet to the XSLT processor. The specification defines a second
root element in the XSLT namespace, called xsl:transform
. This element is identical to
xsl:stylesheet
in every way but
name, and can be used in place of xsl:stylesheet
with no change in
meaning.
The id
attribute is
optional. However, an identifier would certainly come in handy if this
stylesheet were part of a larger XML document (as would be the case
for an embedded stylesheet). The XML specification states that any
attribute of type ID (not necessarily named id
, but of the data
type ID declared in the DTD) must be unique within any XML
document. Use of an ID attribute on a stylesheet is powerful if you
are dynamically generating several stylesheets collected together in a
larger composite document.
The version
attribute
is required as it indicates which version of XSLT is being used. All
xsl:stylesheet
elements must have
the version
attribute. The root
element of simplified stylesheets must also have a version
attribute explicitly associated with
the XSLT namespace, as shown in Example 6-1.
It is strongly recommended that you give a namespace prefix to the stylesheet elements to distinguish it from other elements that are part of the transformation or part of a larger document that contains the stylesheet. The URI of the namespace must be the W3C URI http://www.w3.org/1999/XSL/Transform.
A typical stylesheet element may start like this:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
In this example, the namespace and the version have been
presented, but no id
attribute is
present.
Since XSLT can generate output, which is XML, HTML, or any other
format, it is important to specify which form the output should take.
This is done using the xsl:output
element, which requires a single attribute:
<xsl:output method="xml"/>
The value of the method
attribute can be xml
, html
, or text
. The meaning of each of these values is
roughly what you would expect. If the output should be XHTML, use the
xml
value. For all formats that are
not XML or HTML, the text
method
allows control over each byte of the output, but the intended use is
to generate text-based formats. If you need to generate formats such
as RTF or any of the TeX-based languages, text
is the right value to use. Many
applications that require other formats can be satisfied by generating
an XSL-FO document and then processing it using a processor that has a
lot of information about details of the target format.
If the stylesheet does not contain an xsl:output
element, or if the method
attribute is not specified, the
output is XML.
The xsl:template
element is regularly used to accomplish a great deal of work in the
transformation process. This element is an XSLT instruction, and
usually specifies a pattern for its invocation or defines a name so
that it can be called by other parts of the XSL document. The body of
the xsl:template
element contains
the output markup for when the template is either called or matched by
the XSLT processor.
The attributes of the template element define optionally
its name
and matching rule
(match
). In addition to these
attributes, mode
and priority
are available as well. The mode
is used to indicate a namespace prefix
to be considered by the XSLT processor when the xsl:apply-templates
instruction (described
in the next section) is used with a specific mode. The priority
attribute is used to define a
priority when the template is part of a collection of template
elements that match the same pattern. In other words, when the XSLT
processor has multiple templates to choose from, it defers to priority
if specified.
The most important attribute here is match
. The match
attribute contains an XPath expression
used to determine when the processor has hit the target element in the
source XML document. For example, in the earlier address record,
rather than parsing the document with SAX waiting for your event, use
the following match
attribute and
XPath syntax to hit the first address line:
<xsl:template match="/addr-record/address1">
This expression starts with the root element addr-record
and then further selects its
child address1
. To display the
contents of this field, you could use the same expression in your
select
attribute (covered a little
later in this chapter).
Earlier we created a template element to match an entire XML document and produce a complete HTML document. You can also use the template elements to match any element within the XML source document:
<xsl:template match="/addr-record/address1"> <html> <head> <title>Transformed Address Record</title> </head> <body> <p>We have matched /addr-record/address1</p> <p><xsl:value-of select="/addr-record/address1"/></p> </body> </html> </xsl:template>
In this example, you are matching an element address1
that is a child of the root
addr-record
element and then
processing several rules and content. When the template is
instantiated by the XSLT processor, it outputs the child elements of
the template (in this case HTML) and processes any other XSLT elements
contained therein. The result is the HTML written to standard output
by the XSLT processor. If you run this modified version of the
stylesheet against the XML document, you get the HTML expected in the
previous code listing, but you also get the rest of the XML document’s
character data trailing the HTML. This is because no instructions were
given for the rest of the character data, so it is simply dumped out.
The xsl:apply-templates
element
allows you to nest rules within each other to produce deeply nested
documents that are transformed as expected.
When you have a document that contains nested
structures, the apply-templates
element is used to recursively apply transformation rules throughout
the document. An easy example that demonstrates the concept of nested
structures is formatted text, wherein paragraphs may contain sentences
with bold typeface of multiple colors, code examples, or other
formatting structures that may appear nested within themselves.
Another deeply nested structure is a filesystem. A directory can contain any number of files and subdirectories. Each subdirectory follows the same content rule as any other and may contain any number of files and subdirectories. The resultant tree can become quite complex.
When dealing with XML documents containing nested structures, it
may be desirable to establish a set of rules (templates) for specific
tags, but allow those tags and rules to be nested inside each other.
You can use the apply-templates
elements to accomplish this. Consider the following XML:
<deep-nest> <title>Sample Text</title> <big>T</big>his is an example of <red>Fancy Text</red> that comes in <blue>m<big>u</big></blue><green>l<big> t</big></green><blue>i<big>p</big> </blue><green>l<big>e</big></green> colors. Many of <bold>these</bold> elements are <big><green>N</green> <blue>E</blue><green>S</green><blue>T</blue> <green>E</green><blue>D</blue></big> within each other. </deep-nest>
This XML fragment contains elements with other elements within
them. There is no set order as to which tags can be embedded within
others, as there is not a specified DTD. To account for this nesting
in your template elements, use the xsl:apply-templates
instruction. For
example, the big
element can occur
within a color element, a bold
element, or a title
element.
Therefore, its template
element
is:
<xsl:template match="big"> <font size="5"><xsl:apply-templates/></font> </xsl:template>
Wherever there is a big
element, it is replaced with the font
tag. Furthermore, any content within
the big
tag is processed against
any other template patterns since the xsl:apply-templates
instruction is
specified. Now let’s take a look at the whole stylesheet used to
process the XML:
<?xml version="1.0" encoding="iso-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"/> <xsl:template match="deep-nest"> <html><body><xsl:apply-templates/></body></html> </xsl:template> <xsl:template match="title"> <h1><xsl:apply-templates/></h1> </xsl:template> <xsl:template match="big"> <font size="5"><xsl:apply-templates/></font> </xsl:template> <xsl:template match="red"> <font size="3" color="#FF0000"><u> <xsl:apply-templates/></u></font> </xsl:template> <xsl:template match="blue"> <font color="#0000FF"><xsl:apply-templates/></font> </xsl:template> <xsl:template match="green"> <font color="#00FF00"><b><xsl:apply-templates/></b></font> </xsl:template> <xsl:template match="bold"> <b><i><xsl:apply-templates/></i></b> </xsl:template> </xsl:stylesheet>
The key to this stylesheet is well-formedness. Every XML element
in the source document is accounted for in the stylesheet, and each
defers to further processing by placing xsl:apply-templates
square in the middle. If
you run the XML and stylesheet through your XSLT processor, you get
the following HTML:
<html> <body> <h1>Sample Text</h1> <font size='5'>T</font>his is an example of <font color='#FF0000' size='3'> <u>Fancy Text</u> </font> that comes in <font color='#0000FF'>m<font size='5'>u</font> </font> <font color='#00FF00'> <b>l<font size='5'> t</font></b> </font> <font color='#0000FF'>i<font size='5'>p</font> </font> <font color='#00FF00'> <b>l<font size='5'>e</font></b> </font> colors. Many of <b><i>these</i></b> elements are <font size='5'> <font color='#00FF00'> <b>N</b> </font> <font color='#0000FF'>E</font> <font color='#00FF00'> <b>S</b> </font> <font color='#0000FF'>T</font> <font color='#00FF00'> <b>E</b> </font> <font color='#0000FF'>D</font> </font> within each other. </body> </html>
The xsl:value-of
element generates output from an expression. It has two possible
attributes: select
and disable-output-escaping
. The select
attribute is mandatory as it’s used
to generate the replacement content. The select
attribute takes an XPath expression.
Given the XML <a><b><c
id="c">content</c></b></a>
, the
following expression produces the word “content.”
<xsl:value-of select="/a/b/c"/>
To retrieve an attribute of an element, use the @
symbol in your select
attribute:
<xsl:value-of select="/a/b/c/@id"/>
The disable-output-escaping
attribute causes the XSLT processor to suppress encoding of characters
that could be confused with markup. This can be useful when generating
text output. For example, consider the document:
<doc>A & B</doc>
and this template:
<xsl:template match="doc"> <xsl:value-of select="text( )" disable-output-escaping="yes"/> </xsl:template>
If disable-output-escaping
were allowed to have its default value of no
, the result of the template would be
presented as A & B
— but
when the attribute is set to yes
,
the presentation is A & B
. This
is not needed if the output method is set to text using the xsl:output
element.
We have already used the xsl:value-of
element in the previous
examples in this chapter, as it is core to XSLT.
The xsl:for-each
element allows you to iterate through certain element types inside a
template match. It has a mandatory select
attribute that defines the node set
to be iterated. The select
attribute can contain anything that results in a collection of
elements or nodes, and can be as simple as an element name or another
type of path expression.
The xsl:for-each
element is
helpful when you are working with mixed content and want only to
transform a subset of elements within a document. For example, the
following purchases
XML document
describes multiple types of purchases:
<?xml version="1.0"?> <purchases> <product name="floppy disk" price="3.50"/> <service name="web updates" price="6.95"/> <product name="ink-jet cartridge" price="19.95"/> <service name="consulting" price="150h"/> </purchases>
If you are interested only in the product purchases and not
services, you could use the for-each
element to select only the product
elements:
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/">
<html><body><xsl:apply-templates/>
</body></html>
</xsl:template>
<xsl:template match="purchases">
<xsl:for-each select="product">
<p>Product: <xsl:value-of select="./@name"/>
Price: <xsl:value-of select="./@price"/></p>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
This stylesheet generates HTML detailing information about products, but not about services.
XSLT is a substantial programming language and extends well beyond the scope of this book. In addition to the elements covered here that allow you to select, search, and iterate source XML, XSLT features all sorts of standard language features such as control structures, conditionals, variables, and functions. There are several resources available from which you can learn more about XSLT; if you are considering using XSLT for your projects, a good tutorial introduction is well worth the time.
3.145.66.94