[So what do you do when a Florida storm wakes you up at 3:30am? You get up
and start an XSLT post]
First of all, sorry this has taken so long to post. My mom passed away
between posts. Generally, I put up technical stuff that I have learned doing my
normal job. I learned XSLT awhile ago, and so have never really put it down, so
you forget a few things here and there… I needed a little bit of time to put
this post together. Especially since the tools have gotten better. VS2005
now has pretty nice XSLT support built-in (which I will describe). Prior to
this I had to resort to using various tools that I found online to do this.
Introduction
This topic builds on what we learned in XSLT
for the Uninitiated Part 1: Beginning Xpath. So if you haven’t read
that post I would strongly suggest that you do so.
We’ll start with a fairly simple XML file and do a fairly common task (turn
it into tabular data). Here’s our XSLT file:
<?xml version="1.0" encoding="utf-8" ?>
<data>
<person>
<name First="Jay" Last="Kimble" />
<address line="1">123 Test</address>
<address line="2">Box 778</address>
<city>Some Place</city>
<state>FL</state>
<postal>12345</postal>
<country>USA</country>
</person>
<person>
<name First="Bill" Last="Gates" />
<address line="1">1234 Test</address>
<city>Some Place</city>
<state>WA</state>
<postal>54321</postal>
<country>USA</country>
</person>
<person>
<name First="Don" Last="Xml" />
<address line="1">234 Test</address>
<city>Some Place</city>
<state>NJ</state>
<postal>54321</postal>
<country>USA</country>
</person>
</data>
So we have data with person elements in it. Let me give you a very basic
tabular XSLT and then I’ll discuss it.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/">
<table>
<tr>
<th>Name</th>
</tr>
<xsl:apply-templates select="//person" />
</table>
</xsl:template>
<xsl:template match="person">
<tr>
<td>
<xsl:value-of select="./name/@First"/> <xsl:value-of select="./name/@Last"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
Let’s take this line by line.
1) Skipping XML Declaration (if you need to know about it go look it up)
2) <xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
This is the standard Stylesheet declaration. We are using the 1.0 spec
(and, yes, there is a 2.0 spec out there). The “xmlns:xsl” defines where the definition for the
“xsl:“ namespace comes from (BTW, namespaces in XML are defined with
a colon preceding the element).
3) <xsl:output method="html"/> A rather interesting XSL tag that lets the processor
know that we will be outputting html instead of XML, so it will make modifications to
the output tree if the root output node is html. You can also output text and
XML. “text” means that the tags will be stripped and only the text
part of the tags will be available. The important thing to note is that you
must produce valid XML (with matching open and close tags) in your output. This
element will cause the processor to do different things with the output once it has
been generated.
4) <xsl:template match="/"> This is the first template and it is the main template. All
nodes that match the xpath expression ‘\’ (root node) are
processed. .
5) <table>…</tr>We’re writing standard HTML tables at this
point.
6) <xsl:apply-templates select="//person" /> this essentially calls all templates that match on
“person” nodes
7) </table>…</xsl:template> Our HTML must be valid XML so we complete the tags from above ending
the table and the template
8) <xsl:template match="person"> Defines a new template that matches
“person” nodes (hey we call one of those in the
<asl:apply-templates> tag)
9) <tr><td> “Again with the HTML
tags.”
10) <xsl:value-of select=" 
./name/@First"/> Finally, we are outputting
some data from the XML file. We are starting at the current node (a person
node), finding the child name node and outputting this name node’s First
attribute (if you’re confused go back to the first post on xpath… this
is an xpath expression).
11)   This one is tricky. We need a
non-blocking space, but the &# combination is reserved for some other things in
XML/XSLT, so use the method to output the ascii character that means non-blocking
space. We’ll deal with this later so you can have
‘ ’
12) <xsl:value-of select="./name/@Last"/>… </xsl:stylesheet> Finally, output the last name (in
the same manner we did the first name) and close all tags including the
stylesheet tag.
Sorting
That data looks awful unsorted. Let’s make some changes to sort it.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/">
<table>
<tr>
<th>Name</th>
</tr>
<xsl:apply-templates select="//person" >
<xsl:sort select="./name/@Last"/>
</xsl:apply-templates>
</table>
</xsl:template>
<xsl:template match="person">
<tr>
<td>
<xsl:value-of select=" ./name/@First"/> <xsl:value-of select="./name/@Last"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
We only added one element really: the <xsl:sort> element which is all that
is needed to sort the data. <xsl:sort> is used to sort the nodeset
(results of an xpath select on an XML document or XML fragment) It
can be used inside of an <xsl:apply-templates> or <xsl:for-each> tag, and
it does the same thing in each (sorts the nodes that are being processed
before they are processed)
Entities – Character Replacements
How to get rid of that   and replace it with . Add these
lines right after the <?xml ?> tag:
<!DOCTYPE xsl:stylesheet [
<!ENTITY nbsp " ">
]>
They define an element which is a character replacement (BTW, I had to look this one
up here… I
had forgotten exactly how to do it). All we really did was make our text more
HTML like (the processor is still using the   )
Show All the data
Here’s the complete XSLT stylesheet that I created:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet [
<!ENTITY nbsp " ">
]>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/">
<table>
<tr>
<th>Name</th>
<th>Address</th>
</tr>
<xsl:apply-templates select="//person">
<xsl:sort select="./name/@Last"/>
</xsl:apply-templates>
</table>
</xsl:template>
<xsl:template match="person">
<tr>
<td style="vertical-align:top">
<xsl:value-of select=" ./name/@First"/> <xsl:value-of
select="./name/@Last"/>
</td>
<td style="vertical-align:top">
<xsl:for-each select="./address">
<xsl:sort select="./@line"/>
<xsl:value-of select="."/><br />
</xsl:for-each>
<xsl:value-of select="./city"/>,
<xsl:value-of select="./state"/>
<xsl:value-of select="./postal"/>
<br />
<xsl:value-of select="./country"/>
<br />
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
Honestly, you should know how it works except the <xsl:for-each > statement
which I only used here for the sake of discussion (I could have used another
<xsl:apply-templates> with a template that matched address nodes).
<xsl:for-each> loops through each node in the select list and let’s you
output the data. You can also use a xsl:sort with a xsl:for-each to sort the
data before the loop occurs.
Some XML purists don’t like the <xsl:for-each> because it coddles
certain procedural programming behaviors (XSLT is what is called declarative
programming). For what its worth, until this article, I usually only ever used
<xsl:for-each>, but will probably be avoiding it going forward.
Closing thoughts
I ran out of time; I really wanted to show you how to show you how to use this with
XSLT with AJAX. I guess we’ll save that for the next post which will be
on advanced techniques (hopefully it won’t take so long this time). I
plan on talking about rendering client-side as well server-side; and there are a few
advantages to each; we’ll also talk about some techniques for dynamic
sorting.. I’ll also be releasing an update of my JAAJAX library
between now and then.
If you can’t wait and want to dig deeper, let me recommend a book to you
since it has been invalueable to me (and I don’t even have an amazon account to
make some cash off of you ). The book will cost you about 12.95 USD.
It’s the XML: Pocket Reference (from O’Reilly) by Robert Eckstein
with Michael Casabianca (I won't link it... find it yourself). Believe it or not this is the only book I’ve
read on the subject. And for a pocket reference it is excellent (mine is
falling apart).
Technorati Tags: XSLT
Posted
04-10-2006 4:07 PM
by
Jay Kimble