14.2.1. Filtering XML Data
If you remember, the Foobar Public Library allowed books on several
different subjects to be entered into its system; mytechbooks.com
wants only the books about computer-related subjects. Fortunately,
the library captured this information in the
subject attribute of the book
element for each book in its XML data. The first task is to filter
out any book whose subject is not "Computers". Once the
technical books have been obtained, they should be formatted into an
HTML page that can be shown to customers visiting mytechbooks.com.
For this company and application, there is no static HTML, since the
page showing new listings must be generated each time it is accessed.
I'm going to use a servlet here for handling these responses.
Although Apache Cocoon would be an excellent choice for converting
the XML data from the library into an HTML response, mytechbooks.com
is under tremendous time pressure to make these book listings
available, and does not want to introduce such a large change into
its system immediately; instead, it would prefer to use XML parsers
and processors and then add Cocoon in as a second-phase addition.
This means that you'll have to handle conversion from XML to
HTML as well as the filtering of the data and the addition of other
presentation-specific items, such as a company logo and menu bar.
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
>
<xsl:template match="books">
<!-- Presentation of User Interface -->
</xsl:template>
<xsl:template match="book">
<table border="0" cellspacing="1" bgcolor="#000000">
<tr>
<td>
<table border="0" cellpadding="3" cellspacing="0">
<tr>
<td width="100%" bgcolor="#00659C" nowrap="nowrap" align="center">
<b><font color="#FFFFFF">
<xsl:value-of select="title" />
</font></b>
</td>
</tr>
<tr>
<td width="100%" align="center" nowrap="nowrap" bgcolor="#FFFFFF">
<font color="#000000"><b>
Author: <xsl:value-of select="author" /><br />
Publisher: <xsl:value-of select="publisher" /><br />
Pages: <xsl:value-of select="numPages" /><br />
Price: <xsl:value-of select="saleDetails/price" /><br />
<br />
</b></font>
<xsl:element name="a">
<xsl:attribute name="href">/servlets/BuyBookServlet?isbn=
<xsl:value-of select="saleDetails/isbn" />
</xsl:attribute>
<font color="#00659C">Buy the Book!</font>
</xsl:element>
</td>
</tr>
</table>
</td>
</tr>
</table>
<br />
</xsl:template>
</xsl:stylesheet>
This template matches the book element, and then
creates a table with a heading in one row, and contents in the second
row. The entire table is within another table with a black
background, which results in the appearance of the table being
surrounded by a beveled black border. The title is inserted into the
header of the table, and the information about the book (author,
publisher, pages, and price) is added to the content of the table.
Finally, a link to a Java servlet, BuyBookServlet,
is provided to allow easy access to purchasing the book. The value of
the book's isbn element is supplied as an
argument to this servlet, which enables it to load the book being
purchased.
WARNING:
In your XSL stylesheet, you should ensure that the line indicating the use of BuyBookServlet and the line with the xsl:value-of element selecting the book's ISBN number is actually one single line. If not, spaces and a carriage return could be inserted into the resultant URL, causing incorrect information to be passed to the servlet. The example stylesheet has this information broken into two lines because of the space constraints of the printed page.
The last addition you need to make to your stylesheet is to ensure
that the new template is applied, and that only books with the
subject "Computers" are passed to the new template. You
can reference the value of the subject attribute
with the @ symbol in your stylesheet, and filter
the requests with the select attribute on the
xsl:apply-templates element:
</td>
<td align="left">
<!-- Handle creation of content for each new *computer* book -->
<xsl:apply-templates select="book[@subject='Computers']" />
</td>
</tr>
</table>
This references the value of the attribute and compares it to a
literal, enclosed within single quotes because the entire XPath
expression is enclosed within double quotes. Because you are
accessing an attribute of a nested element, you'll need to
reference the element by name, and surround the expression on the
element's attribute with brackets. This will ensure that only
books with a subject of "Computers" have templates
applied, and are therefore included in the HTML output. Once the
stylesheet is complete, it can be saved as computerBooks.xsl and referenced
programmatically by a Java servlet, which I'll show you how to
write next.