This post demonstrates you how to use imports and includes to override XSLT templates by describing a style sheet that converts an XML announcement into HTML. The overall goal is to provide default templates, but to allow the user enough latitude to change certain aspects of the style sheet if desired. Other aspects are not changeable. The style sheets work with the following source document:
Listing 1. The source document
<?
xml
version
=
"1.0"
?>
<?
xml-stylesheet
href
=
"style.xsl"
version
=
"1.0"
type
=
"text/xsl"
?>
<
announcement
>
<
headline
>Contest Announcement</
headline
>
<
description
>
Do you love
<
product
>Pop's Homemade Mashed Potato Mix</
product
>?
Are you artistic? Well, here's your big big chance!
Loopy Foods, the company that brings you
<
product
>Pop's Homemade Mashed Potato Mix</
product
>
and <
product
>Aunt Susie's Squash in a Box</
product
>
is hosting a Mashed Potato Sculpting Contest. Send your
entry today. Contest rules are on the back of every box
of <
product
>Pop's Homemade Mashed Potato Mix</
product
>.
</
description
>
<
copyright
/>
</
announcement
>
The goal is to create an HTML page with a style sheet such as this:
Listing 2. The basic style sheet
<?
xml
version
=
"1.0"
?>
<
xsl:stylesheet
version
=
"1.0"
xmlns:xsl
=
"http://www.w3.org/1999/XSL/Transform"
>
<
xsl:template
match
=
"/"
>
<
html
>
<
head
><
title
><
xsl:value-of
select
=
"announcement/headline"
/></
title
></
head
>
<
body
>
<
xsl:apply-templates
/>
</
body
>
</
html
>
</
xsl:template
>
<
xsl:template
match
=
"headline"
>
<
h1
><
xsl:apply-templates
/></
h1
>
</
xsl:template
>
<
xsl:template
match
=
"description"
>
<
p
><
xsl:apply-templates
/></
p
>
</
xsl:template
>
<
xsl:template
match
=
"product"
>
<
b
><
xsl:apply-templates
/></
b
>
</
xsl:template
>
</
xsl:stylesheet
>
The result is a document that creates a paragraph for each announcement, and puts the product names in bold:
Listing 3. The basic transformation results
Creating the template style sheet
Using these templates, an administrator can build a basic style sheet that enables users to use default styles, but allows them to use custom styles if necessary. To do this, you need to include the basic templates in a second style sheet, in this case called import.xsl:
Listing 4. The imported style sheet (import.xsl)
<?
xml
version
=
"1.0"
?>
<
xsl:stylesheet
version
=
"1.0"
xmlns:xsl
=
"http://www.w3.org/1999/XSL/Transform"
>
<
xsl:template
match
=
"headline"
>
<
h1
><
xsl:apply-templates
/></
h1
>
</
xsl:template
>
<
xsl:template
match
=
"description"
>
<
p
><
xsl:apply-templates
/></
p
>
</
xsl:template
>
<
xsl:template
match
=
"product"
>
<
b
><
xsl:apply-templates
/></
b
>
</
xsl:template
>
</
xsl:stylesheet
>
From there, it's a matter of creating a style sheet that imports the main styles. With this import in place, a style sheet that contains only the main template still acts as desired, but if an additional template is added, it overrides the corresponding template in the import:
Listing 5. Overriding imported templates
<?
xml
version
=
"1.0"
?>
<
xsl:stylesheet
version
=
"1.0"
xmlns:xsl
=
"http://www.w3.org/1999/XSL/Transform"
>
<
xsl:template
match
=
"/"
>
<
html
>
<
head
><
title
><
xsl:value-of
select
=
"announcement/headline"
/></
title
></
head
>
<
body
>
<
xsl:apply-templates
/>
</
body
>
</
html
>
</
xsl:template
>
<
xsl:template
match
=
"headline"
>
<
h1
><
xsl:apply-templates
/></
h1
>
</
xsl:template
>
<
xsl:template
match
=
"description"
>
<
p
><
xsl:apply-templates
/></
p
>
</
xsl:template
>
<
xsl:template
match
=
"product"
>
<
b
><
xsl:apply-templates
/></
b
>
</
xsl:template
>
</
xsl:stylesheet
>
Imported style sheets have a lower precedence than the main style sheet, so the product template in the main style sheet is used instead of the imported product template:
Listing 6. Overridden template results
Even when a template is overridden, you still have the opportunity to use the imported templates, however, using the apply-imports
option:
Listing 7. Applying imports
...
</
html
>
</
xsl:template
>
<
xsl:template
match
=
"product"
>
<
i
><
xsl:apply-imports
/></
i
>
</
xsl:template
>
</
xsl:stylesheet
>
As a result, both the original template and the imported template are executed:
Listing 8. Using overridden templates
The difference between importing and including
An import element must always be a top-level element, and must always come before any other elements. This requirement has a specific consequence in terms of precedence. In an XSLT style sheet, the last template processed has precedence over everything that has come before, so imported templates are always overridden. Imported templates also become part of the import tree, so they're available for the apply-imports
element.
On the other hand, style sheets can also be included using the include element, which simply adds them to the main style sheet at the point in which they're included. What's more, while a style sheet must be included at the top level, it can be added at any point, so it can easily be added at the bottom of the page, overriding any templates the user might add.
For example, you could create an included style sheet that sets the copyright information, called include.xsl:
Listing 9. The included style sheet (include.xsl)
<?
xml
version
=
"1.0"
?>
<
xsl:stylesheet
version
=
"1.0"
xmlns:xsl
=
"http://www.w3.org/1999/XSL/Transform"
>
<
xsl:template
match
=
"copyright"
>
<
p
>Copyright 2003, Loopy Foods</
p
>
</
xsl:template
>
</
xsl:stylesheet
>
When this style sheet is included at the end of the main style sheet, it overrides any other templates:
Listing 10. Including the style sheet
...
<
xsl:template
match
=
"product"
>
<
i
><
xsl:apply-imports
/></
i
>
</
xsl:template
>
<
xsl:template
match
=
"copyright"
>
<
p
><
big
>Copyright now, by ME</
big
></
p
>
</
xsl:template
>
<
xsl:include
href
=
"include.xsl"
/>
</
xsl:stylesheet
>
So even though the main style sheet includes a copyright
template, the included template is still used:
Listing 11. Inclusion results
...
Sculpting Contest. Send your entry today. Contest rules are on the
back of every box of <
i
><
b
>Pop's Homemade Mashed Potato Mix</
b
></
i
>.
</
p
>
<
p
>Copyright 2003, Loopy Foods</
p
>
</
body
>
</
html
>
Remember that the precedence is a matter of position; if the style sheet (include.xsl
) had been included at the start of the main style sheet rather than the bottom, the copyright
template in the main stylesheet (style.xsl
) would have been used instead.