XSLT has some built-in, default rules that we've already seen in
action. For example, the default rule for text nodes is to add the
text in that node to the output document.
The most important default rule applies to elements and can be
expressed like this:
<xsl:template match="/ | *">
<xsl:apply-templates/>
</xsl:template>
This rule is simply there to make sure that every element, from
the root on down, is processed with <xsl:apply-templates/> if
you don't supply some other rule. If you do supply another rule, it
overrides the corresponding default rule.
The default rule for text can be expressed like this, where, by
default, the text of a text node is added to the output document:
<xsl:template match="text()">
<xsl:value-of select="."/>
</xsl:template>
The same kind of default rule applies to attributes, which are
added to the output document with a default rule like this:
<xsl:template match="@*">
<xsl:value-of select="."/>
</xsl:template>
By default, processing instructions are not inserted in the output
document, so their default rule can be expressed simply like
this:
<xsl:template match="processing-instruction()"/>
The same goes for comments, whose default rule can be expressed
this way:
<xsl:template match="comment()"/>
The upshot of the default rules is that if you don't supply any
rules at all, _all the parsed character data in the input document is
inserted in the output document. Here's what an XSLT style sheet with
no explicit rules looks like:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
</xsl:stylesheet>
Here's the results of applying this style sheet to planet.xml:
<?xml version="1.0" encoding="UTF-8"?>
Mercury
.0553
58.65
1516
.983
43.4
Venus
.815
116.75
3716
.943
66.8
Earth
1
1
2107
1
128.4
XSLT Rules and Internet Explorer
One of the problems of working with XSLT in Internet Explorer is
that that browser doesn't supply any default rules. You have to
supply all the rules yourself.
Altering Document Structure Based on Input
So far, the templates in this chapter have been fairly rigid
skeletons, specifying exactly what should go into the output document
in what order. But you can use XSLT elements such as
<xsl:element>, <xsl:attribute>, <xsl:text>, and so
on to create new nodes on the fly, based on what you find in the
input document. I'll take a look at how this works now.
Creating Attribute Templates
Say that you wanted to convert the text in some elements to
attributes in other elements-how could you do it? Attribute values
must be quoted in XML, but you can't just use expressions like these,
where I'm taking the values of <NAME>, <MASS>, and
<DAY> elements and trying to make them into attribute
values:
<xsl:template match="PLANET">
<PLANET NAME="<xsl:value-of
select='NAME'/>"
MASS="<xsl:value-of
select='MASS'/>"
DAY="<xsl:value-of
select='DAY'/>"
/>
This won't work because you can't use < inside attribute
values, as I have here. Instead, you must use an expression like
{NAME}; here's the proper XSLT:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="PLANETS">
<HTML>
<HEAD>
<TITLE>
Planets
</TITLE>
</HEAD>
<BODY>
<xsl:apply-templates select="PLANET"/>
</BODY>
</HTML>
</xsl:template>
<xsl:template match="PLANET">
<PLANET NAME="{NAME}"
MASS="{MASS}"
DAY="{DAY}"
/>
</xsl:template>
</xsl:stylesheet>
Here's the resulting document-note that I've been able to convert
the _values in various elements to attributes:
<HTML>
<HEAD>
<TITLE>
Planets
</TITLE>
</HEAD>
<BODY>
<PLANET DAY="58.65" MASS=".0553" NAME="Mercury">
</PLANET>
<PLANET DAY="116.75" MASS=".815" NAME="Venus">
</PLANET>
<PLANET DAY="1" MASS="1" NAME="Earth">
</PLANET>
</BODY>
</HTML>
You can even include multiple expressions in curly braces, like
this, where I'm adding the units for mass and day measurements from
the UNITS attribute in the original elements:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="PLANETS">
<HTML>
<HEAD>
<TITLE>
Planets
</TITLE>
</HEAD>
<BODY>
<xsl:apply-templates select="PLANET"/>
</BODY>
</HTML>
</xsl:template>
<xsl:template match="PLANET">
<PLANET NAME="{NAME}"
MASS="{MASS}
{MASS/@UNITS}"
DAY="{DAY}
{DAY/@UNITS}"
/>
</xsl:template>
</xsl:stylesheet>
Creating New Elements
You can create new elements with the <xsl:element> element.
For example, say that I store the name of planets in a NAME attribute
instead of a <NAME> _element in planets.xml, like this:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xml" href="planets.xsl"?>
<PLANETS>
<PLANET NAME="Mercury">
<MASS UNITS="(Earth =
1)">.0553</MASS>
<DAY
UNITS="days">58.65</DAY>
<RADIUS
UNITS="miles">1516</RADIUS>
<DENSITY UNITS="(Earth =
1)">.983</DENSITY>
<DISTANCE UNITS="million
miles">43.4</DISTANCE><!-At perihelion->
</PLANET>
.
.
.
I could create a new element using the name of the planet with
<xsl:element>, supplying the name of the new planet with the
name attribute, and enclosing a <MASS> element this way:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="PLANETS">
<HTML>
<HEAD>
<TITLE>
Planets
</TITLE>
</HEAD>
<BODY>
<xsl:apply-templates select="PLANET"/>
</BODY>
</HTML>
</xsl:template>
<xsl:template match="PLANET">
<xsl:element name="{@NAME}">
<MASS><xsl:value-of select="MASS"/></MASS>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Here is the result, where I've created a new <mercury>
element:
<HTML>
<HEAD>
<TITLE>
Planets
</TITLE>
</HEAD>
<BODY>
<Mercury>
<MASS>.0553</MASS>
</Mercury>
.
.
.
In this way, you can create new elements and name them when the
XSLT transformation takes place.
Creating New Attributes
Just as you can create new elements with <xsl:element> and
set the element name and content under programmatic control, you can
do the same for attributes using the <xsl:attribute>
element.
Here's an example; in this case, I'm creating new <PLANET>
elements with attributes corresponding to the various planet names,
and values taken from the COLOR attribute in the original
<PLANET> elements:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="PLANETS">
<HTML>
<HEAD>
<TITLE>
Planets
</TITLE>
</HEAD>
<BODY>
<xsl:apply-templates select="PLANET"/>
</BODY>
</HTML>
</xsl:template>
<xsl:template match="PLANET">
<PLANET>
<xsl:attribute
name="{NAME}">
<xsl:value-of select="@COLOR"/>
</xsl:attribute>
</PLANET>
</xsl:template>
</xsl:stylesheet>
Here are the results; as you can see, I've created new attributes
on the fly, using the names of the planets:
<HTML>
<HEAD>
<TITLE>
Planets
</TITLE>
</HEAD>
<BODY>
<PLANET Mercury="RED">
</PLANET>
<PLANET Venus="WHITE">
</PLANET>
<PLANET Earth="BLUE">
</PLANET>
</BODY>
</HTML>