XSL Templates by Example
by James
Tauber
Version:1999-03-03
NOTE: THIS DOCUMENT IS NOW OUT OF DATE. I WILL UPDATE IT AT
SOME STAGE TO REFLECT THE LATEST XSLT DRAFT.
This document briefly outlines some of the
"real-life" templates I use for generating XMLSOFTWARE. The site is authored in
XML and transformed to HTML using XT and a series of stylesheets (some of which
are generated via other stylesheets). Here I have taken extracts that
demonstrate the different things XSL can do, have ordered them in increasing
complexity and added some commentary on what each does.
The templates here follow the latest XSL Working
Draft and work on the latest version of XT. I doubt all of them work on
IE5b2.
Feedback is welcome and encouraged
Generating HTML
XSL allows the result tree to be serialised as
non-XML. In my case, I want to produce HTML 4.0 which isn't fully XML. Empty
element tags need to be <BR>, for example, not <BR/>. To specify to
XT (and other XSL processors) that the result tree is to be serialised as HTML
4.0, I use the following document element start-tag:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/TR/WD-xsl"
xmlns="http://www.w3.org/TR/REC-html40"
result-ns=""
> |
Note that the namespace attributes also indicate
that I am using the "xsl" prefix for my XSL elements and no prefix for my result
tree vocabulary. This is an arbitrary choice.
Generating XSL
I have a couple of stylesheets that are themselves
generated by applying a stylesheet to an XML document. To distinguish the result
vocabulary from the actual XSL used in the "meta" stylesheet, we (as always) use
namespaces. One encounters the problem, though, that both namespaces end up
having the same URI which makes them, in effect, the same namespace.
Fortunately, XSL provides for this with a "quote:" before the URI used for the
result namespace. So in my "meta" stylesheet for generating other stylesheets, I
use as my document element start-tag:
<ixsl:stylesheet
xmlns:ixsl="http://www.w3.org/TR/WD-xsl"
xmlns:xsl="quote:http://www.w3.org/TR/WD-xsl"
result-ns="xsl"
> |
Again, the prefixes are arbitrary. Don't ask me why
I use "ixsl". I had some reason at the time :-)
Invoking XT
I have a script:
~/java-rt/bin/jre -classpath ~/jars/rt.jar:~/jars/sax.jar:~/jars/xp.jar:~/jars/xt.jar \
com.jclark.xsl.sax.Driver $1 $2 $3
|
that I use to invoke xt on my web host's Linux box.
That way I can just type:
xt.sh filename-of-input filename-of-stylesheet filename-of-output
|
On a Windows platform, you can get an executable so
you can just type:
xt filename-of-input filename-of-stylesheet filename-of-output
|
Actually, I use make, and my makefile has things
like:
xmlsoftware-site/index.html: content/xmlsoftware/index.xml xsl/xmlsoftware/xmlsoftware.xsl \
working/new-updated.xml working/date.xml
scripts/xt.sh $< xsl/xmlsoftware/xmlsoftware.xsl $@
|
The HTML file has obvious dependencies on the XML
file and the XSL stylesheet. The other two dependencies are automatically
generated entities (for the what's new/updated and the date respectively) that
are referenced in index.xml
The Templates
Here are the example templates, along with sample
input and result.
Task
Transform Paras into Ps
Input
Output
Template(s)
<xsl:template match="Para">
<P><xsl:apply-templates/></P>
</xsl:template> |
Task
Transform Titles of Sections into H3s
Input
<Section>
<Title>...</Title>
...
</Section> |
Output
Template(s)
<xsl:template match="Section/Title">
<H3><xsl:apply-templates/></H3>
</xsl:template> |
Task
Transform a Link with a URL attribute into an A with
an HREF attribute
Input
<Link URL="http://www.jtauber.com/">My Site</Link> |
Output
<A HREF="http://www.jtauber.com/">My Site</A> |
Template(s)
<xsl:template match="Link">
<A HREF="{@URL}"><xsl:apply-templates/></A>
</xsl:template> |
Task
Transform a Category into a table row with the Title
of the Category being a link to the category's page (named after the category's
ID)
Input
<Category ID="xsl">
<Title>XSL Editors / Tools</Title>
...
</Category> |
Output
<TR><TD><A HREF="/xsl/">XSL Editors / Tools</A></TD></TR> |
Template(s)
<xsl:template match="Category">
<TR><TD><A HREF="/{@ID}/"><xsl:value-of select="Title"/></A></TD></TR>
</xsl:template> |
Task
Transform an Email element to an A with mailto HREF
and the email as the content too
Input
<Email>jtauber@jtauber.com</Email> |
Output
<A HREF="mailto:jtauber@jtauber.com">jtauber@jtauber.com</A> |
Template(s)
<xsl:template match="Email">
<A HREF="mailto:{.}"><B><xsl:apply-templates/></B></A>
</xsl:template> |
Notes
I could have used <xsl:value-of select="."/>
instead of <xsl:apply-templates/> but this way I could have further markup
in the Email element's content that gets transformed.
Task
Take Products in the list of new and updated
products and generate a list item that includes a link to the product using the
name of the product as the linking text and the category and ID of the product
to form to URL of the link. Also include the version number of the product
formatted as the CSS class "annotation"
Input
<NewUpdatedProduct>
<Product ID="xt" Updated="1999-01-15">
<Name>XT</Name>
<Version>19990115</Version>
<category>xsl</Category>
...
</Product>
...
</NewUpdatedProduct> |
Output
<UL>
<LI><A HREF="/xsl/#xt">XT</A>
<BR><SPAN CLASS="annotation">version: 19990115</SPAN></LI>
...
</UL> |
Template(s)
<xsl:template match="NewUpdatedProduct">
<UL><xsl:apply-templates/></UL>
</xsl:template>
<xsl:template match="NewUpdatedProduct/Product">
<LI><A HREF="/{Category}/#{@ID}"><xsl:value-of select="Name"/></A>
<BR/><SPAN CLASS="annotation">version: <xsl:value-of select="Version"/></SPAN>
</LI>
</xsl:template> |
Task
Produce an HTML document with a title specific to
the product category unless it is not a product category page we are
transforming.
Input
<ProductPage>
<Title>XSL Editors / Tools</Title>
...
</ProductPage> |
Output
<HTML>
<HEAD>
<TITLE>XSL Editors / Tools at XMLSOFTWARE</TITLE>
...
</HEAD>
...
</HTML> |
Input
Output
<HTML>
<HEAD>
<TITLE>XMLSOFTWARE: The XML Software Site</TITLE>
...
</HEAD>
...
</HTML> |
Template(s)
<xsl:template match="/">
<HTML>
<HEAD>
<xsl:choose>
<xsl:when test="ProductPage/Title">
<TITLE><xsl:value-of select="ProductPage/Title"/> at XMLSOFTWARE</TITLE>
</xsl:when>
<xsl:otherwise>
<TITLE>XMLSOFTWARE: The XML Software Site</TITLE>
</xsl:otherwise>
</xsl:choose>
...
</HEAD>
...
</HTML>
</xsl:template> |
Task
Given a ProductSelect element with attribute Type
equally "xsl", select Products from the ProductList whose Categories are
"xsl".
Input
<ProductSelect Type="xsl"/>
...
<ProductList>
<Product ID="xt" Updated="1999-01-15">
<Name>XT</Name>
...
<Category>xsl</Category>
...
</Product>
</ProductList> |
Output
the output is the transformed Products that are in the category xsl. |
Template(s)
<xsl:template match="ProductSelect">
<xsl:choose>
...
<xsl:when test='.[@Type="xsl"]'>
<xsl:apply-templates select='//ProductList/Product[Category="xsl"]'/>
</xsl:when>
</xsl:choose>
</xsl:template> |
Notes
The template actually includes an xsl:when for each
category. The entire template is itself generated by applying a stylesheet to
the list of categories. See below for the template that does this.
Task
Generate the stylesheet template used above.
Input
<CategoryList>
...
<Category ID="xsl">
<Title>XSL Editors / Tools</Title>
...
</Category>
</CategoryList> |
Output
<xsl:template match="ProductSelect">
<xsl:choose>
...
<xsl:when test='.[@Type="xsl"]'>
<xsl:apply-templates select='//ProductList/Product[Category="xsl"]'/>
</xsl:when>
</xsl:choose>
</xsl:template> |
Template(s)
<ixsl:template match="CategoryList">
<ixsl:element name="xsl:stylesheet">
<ixsl:element name="xsl:template">
<ixsl:attribute name="match">ProductSelect</ixsl:attribute>
<ixsl:element name="xsl:choose">
<ixsl:apply-templates/>
</ixsl:element>
</ixsl:element>
</ixsl:element>
</ixsl:template>
<ixsl:template match="Category">
<ixsl:element name="xsl:when">
<ixsl:attribute name="test">.[@Type="<ixsl:value-of select="@ID"/>"]</ixsl:attribute>
<ixsl:element name="xsl:apply-templates">
<ixsl:attribute name="select"
>ProductList/Product[Category="<ixsl:value-of select="@ID"/>"]</ixsl:attribute>
</ixsl:element>
</ixsl:element>
</ixsl:template> |
Notes
This example uses XSL as the result vocabulary. This
was achieved using the following document element start tag: <ixsl:stylesheet
xmlns:ixsl="http://www.w3.org/TR/WD-xsl"
xmlns:xsl="quote:http://www.w3.org/TR/WD-xsl" result-ns="xsl">
Task
Copy through any element that doesn't have a
template. Include attributes and content.
Input
<AnyElement AnyAttribute="AnyValue">AnyContent</AnyElement> |
Output
<AnyElement AnyAttribute="AnyValue">AnyContent</AnyElement> |
Template(s)
<xsl:template match="*|@*" priority="-1">
<xsl:copy>
<xsl:apply-templates select="@*|*|text()"/>
</xsl:copy>
</xsl:template> |
Notes
This is used in a stylesheet that preprocessed an
XML document before it is passed on to another stylesheet. Only the odd element
is altered, hence the need for this "let everything else through"
template.