Published: Wednesday, April 23, 2003
Displaying Hierarchical XML Data of an Arbitrary Depth Using XSLT, Part 2
By Scott Mitchell
Read Part 1
In Part 1 we examined the problem of using XSLT to display
XML data that has an arbitrary amount of depth. Furthermore, we examined one suboptimal approach
to displaying such XML content. In this part, we'll see a concise way that will display
XML data for an arbitrary depth.
Using Recursion to Display an Arbitrary Hierarchy Depth
What we'd like to be able to do is have all of the folders and files displayed, properly indented,
regardless of the maximum folder depth. If you have a computer science background, you likely notice
that this particular problem is identical to completely traversing a tree in pre-order. (If that last
sentence makes no sense to you, don't worry! :-)). Essentially, what we need to do is create
a means to display a given folder, its files, and its subfolders. Then, for each folder, we encounter,
we simply want to enact this routine. This approach can be summarized in the following steps:
- Display the folder's name.
- Display the folder's files.
- For each subfolder, go to Step 1.
This explanation involves using a technique called recursion. Something is said to be
recursive if it is described in terms of itself. Our three steps above are recursive because Step 3
is defined in terms of Step 1. (For more information on recursion, be sure to read:
Recursion, Why It's Cool.)
To accomplish this in XSLT we have to create two <xsl:template> tags: one that
handles the filesystem/drive elements, and one that handles an arbitrary <folder>
element. The first <xsl:template> is fairly straightforward:
<xsl:template match="/filesystem/drive">
<xsl:value-of select="@letter">
<ul>
<xsl:apply-templates select="folder" />
</ul>
</xsl:template>
|
As you can see, this template matches each filesystem/drive element and displays its
letter attribute. Next, it uses the <xsl:apply-templates> tag, which
then applies a specified template. Specifically, this is the template that (recursively) displays the
<folder> elements. The syntax for the template can be seen below:
<xsl:template match="folder">
<li><xsl:value-of select="@name"></li>
<ul>
<xsl:for-each select="file">
<li><xsl:value-of select="text()"></li>
</xsl:for-each>
</ul>
<ul>
<xsl:apply-templates select="folder" />
</ul>
</xsl:template>
|
Here, the template displays the folder's name attribute, and all of its <file>
elements. Then, it recursively displays the folder's <folder> elements,
using the same template.
The last piece of the puzzle is to put the two templates together in a single XSLT file:
<?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="/filesystem/drive">
<b><xsl:value-of select="@letter" /></b><br />
<ul>
<xsl:apply-templates select="folder" />
</ul>
</xsl:template>
<xsl:template match="folder">
<li><xsl:value-of select="@name" /></li>
<ul>
<xsl:for-each select="file">
<li><i><xsl:value-of select="text()" /></i></li>
</xsl:for-each>
</ul>
<ul>
<xsl:apply-templates select="folder" />
</ul>
</xsl:template>
</xsl:stylesheet>
|
[
View a Live Demo!]
Conclusion
In this article we examined how to use XSLT to display XML data in an HTML-format when the XML data is
comprised of an arbitrary depth. The secret was to use two templates, with one template applied
recursively. Be sure to check out the live
demo, and the XML FAQs for more
information about XML and XSLT!
Happy Programming!
By Scott Mitchell