To get the most out of this article you should be familiar with Web applications based on the HTTP protocol, and the HTTP request-response mechanism. You should also know the Java programming language and how to use Java servlets as access points for Web applications.
So you have the idea (or even a design) for a complex Web application. You know it would be more profitable if it were accessible not only from standard Web browsers, but also via Wireless Access Protocol (WAP) devices and maybe even voice. You're going to use XML for communication between the core application and the server processes dealing with user interaction. For each supported client format, the user interface will consist of many views for all possible user actions, but all these views will share a common design -- your corporate design -- and some common hidden information.
In more complex output formats, like HTML, a substantial part of the browser window will display more or less the same information -- links, images, and the like -- all the time. Since you're planning to use XSLT to transform the XML that is produced by the core system to the different client formats, you realize that just one XSL style sheet per supported client format is not practical. It would be much too big and difficult to maintain. In short, you need an efficient way of structuring your XML data and all these XSL style sheets.
To explain and demonstrate the framework that solves the problem, I've written a simple Web-based calendar application called WebCal. It maintains calendars for multiple users and offers the following features:
- New users may register for the calendar via a registration page. Users provide personal information, and are assigned a username and password for the system.
- Registered users can log in to the system using a login page.
- Once logged in, users can switch between day, month, and year views of their calendars (calendar views).
- Users can create, view, modify, and delete events.
- Events have a summary, a description, a start time and an end time. The start and end times and summary are displayed in the calendar views.
Figure 1 shows a screen shot of the login page:
Figure 1. The WebCal login page

Users can work with their calendars once they've logged in successfully. A typical calendar view looks like the one in Figure 2. It displays the week of Feb 11, 2001 to Feb 17, 2001.
Figure 2. The WebCal week view

All views are displayed within the blue frame, which contains the application title and logo, some links, the main navigation bar, and a subnavigation bar.
The frame supports multiple navigation bars, for external links, internal views, and internal actions. The main navigation (below the logo) provides links to the calendar views from all views except the login and registration pages. The subnavigation bar allows internal actions, such as creating events from within the calendar views and editing or deleting events from the event view.
The WebCal application demonstrates only XSL style sheets for HTML output, since HTML for standard Web browsers using a standard size display (1024 x 768 or bigger) is typically the most complex output. All the principles are the same for other HTTP-based formats. For compatibility reasons with WebSphere 3.0, which I use as Web server and servlet engine, WebCal is written in Java 1.1.7 (see Resources). It uses a servlet, which can be run in any servlet engine. The servlet uses browser cookies (accepted by all common HTTP-based browsers, including WAP phones) to keep track of user sessions.
WebCal understands a series of request types, which all use their own set of HTTP parameters. In the sample application, everything is done through the servlet:
- Analyzing the HTTP parameters of the request
- Performing the necessary actions
- Generating response XML
- Transforming the XML to HTML (or any other format)
- Sending the response back to the client
Listing 1. Example HTTP request
http://localhost/webcal/WebCalServlet?action=ShowDay&date=2001-02-17 |
Step 1. Basic XML/XSL framework
First we discuss how to structure and generate XML data used by the application. Then the general structure of the XSL style sheets is shown; the style sheets are used to transform the XML data to any desired output format.
XSL transformations from XML to any desired format happen through a series of attempts to match patterns in the XML data. The XML data should be structured to make that pattern matching as easy as possible.
The XML data that is passed from the core of your application to the front end should contain only information necessary for display and further processing. First of all, you need a root element, as shown in Listing 2. It should be the same for all views, because certain parts of the display will also be the same for all views. As we will see, the XSL processor finds this information most easily by matching the root element.
Listing 2. Document header and root element
<?xml version="1.0"?> <!DOCTYPE webcal> <webcal> <!--general stuff--> <!--view specific--> </webcal> |
Since the pages are just templates for form entry and they always look the same, hardly any additional processing and XML data are necessary to display the registration and login pages.
For the calendar views, I need to include information about the period to be displayed. This includes the name and exact date of the days, and all events in that period. Since this simple demo application does not display the description of an event in the calendar views, I do not need to include it in the XML. I store the event id for each event in the XML, since I may want to create a link to a more detailed view for those events.
Listing 3. Representation of a day
<webcal>
...
<day date="2001-02-17">
<event id="..." start="2001-02-17T20:00" end="2001-02-18T06:00">
<summary>Martin's birthday party</summary>
</event>
</day>
...
</webcal> |
Views that display more than one day have several <day>
elements. These elements can be sorted, or processed in the order they appear. For sorting, you can use the date attribute (in ISO8601 format). For the month view, the <day> elements may be grouped into <week> tags. This doesn't require much more computation in the XML generation, and it simplifies things in the XSL processing. Check out the Compute in Java code or XSL? sidebar for more detail.
Displaying an event in a detailed view requires all available event
information. For WebCal this would be the same as Listing
3 plus the event description, which would appear as a <description>
element.
Displaying the view to create an event does not necessarily require
any XML data, but you could include an <event> element to provide
default values. Modifying an event requires all the event data again, in
order to fill the fields of the editing form with the current values.
You'll need some information -- such as the different parts of the frame, the links, and the navigation bars -- for all views when a user is logged in. The subnavigation differs from view type to view type, but it's the same for any two views of the same type (for example, two day views displaying different days). You might also want to include some personal data once a user is logged in. The example app uses just the name and username. It has also proved quite useful to include the HTTP parameters for the current view, so that they become available in the XSL style sheets.
The following code sample shows the complete XML generated for the week that starts on the Sunday before "Martin's birthday party." It is ready to be transformed to the client's preferred format.
Listing 4. Complete XML representing a view
<webcal>
<http-params>
<param name="action" value="ShowWeek"/>
<param name="date" value="2001-02-11"/>
</http-params>
<user>
<login>martin</login>
<firstname>Martin</firstname>
<middlename/>
<lastname>Gerlach</lastname>
</user>
<navigation>
<global>
<main-nav>
<link type="internal" text="Day" href="ShowDay">
<pass-param name="date"/>
</link>
<link type="internal" text="Week" href="ShowWeek">
<pass-param name="date"/>
</link>
<link type="internal" text="Month" href="ShowMonth">
<pass-param name="date"/>
</link>
</main-nav>
<links>
<link type="internal" text="Logout" href="Logout"/>
<link type="external" text="Home" href="http://www.ibm.com/developer"/>
</links>
</global>
<actions>
...
<action name="ShowWeek">
<sub-nav>
<link type="internal" text="New Event" href="ShowNewEvent">
<pass-param name="date"/>
</link>
</sub-nav>
</action>
...
</actions>
</navigation>
<now date="2000-11-07T15:30"/>
<week date="2001-02-11" previous="2001-02-04" next="2001-02-18">
<day date="2001-02-11"/>
<day date="2001-02-12"/>
<day date="2001-02-13"/>
<day date="2001-02-14"/>
<day date="2001-02-15">
<event id="(id1)" start="2001-02-15T18:00" end="2001-02-15T20:00">
<summary>Shopping for Martin's birthday party</summary>
</event>
</day>
<day date="2001-02-16"/>
<day date="2001-02-17">
<event id="(id2)" start="2001-02-17T20:00" end="2001-02-18T06:00">
<summary>Martin's birthday party</summary>
</event>
</day>
</week>
</webcal> |
Only the <week> element is specifically generated for the
week view, everything else is the same for all views and could be saved
in the file system or a database.
Figure 2 shows how the results
of Listing 4 look on the screen. (The necessary XSL transformations are
discussed in Step 2.) If you are running the sample application,
you may append "&format=xml" to the current URL and reload
the page to see the response XML for the current view.
The data to be processed resides on the server. Once accessed, it needs to be formatted into XML. You can use any one of the available XML packages for Java to generate a DOM tree containing the response XML. The following examples refer to XML4J (see Resources).
XML data can be passed around in Java as instances of org.w3c.dom.Document
or org.w3c.dom.Element. The document interface has the advantage of providing
several useful methods to parse the contained elements.
Listing 5. Creating a document with a root node
import org.w3c.dom.*; // DOM interfaces
import org.apache.xerces.dom.*; // DOM implementation for XML4J
...
Document responseXML = createDocument("webcal");
public Document createDocument(String rootName)
{
Document doc = new DocumentImpl();
doc.appendChild(doc.createElement(rootName));
return doc;
} |
Listing 6. Getting the document root element
Element root = doc.getDocumentElement(); |
Listing 7. Appending element <day date="2001-02-17"/> to an element
Element dayElem = doc.createElement("day");
dayElem.setAttribute("date","2001-02-17");
someElement.appendChild(dayElem); |
Listing 8. Appending text to element summaryElem: <summary>This is a summary</summary>
org.w3c.dom.Text textNode = doc.createTextNode("This is a summary");
summaryElem.appendChild(textNode); |
You may want to write your own utility methods to build your application's
XML documents. The parsers in the available XML packages can be used to
read/write XML to and from streams (including files). In the source code, look
at ShowAction.displayResult() or any other ShowAction's generateXML()
method to see how this can be done.
You might also want to consult other developerWorks articles dealing with XML and Java for additional ideas (see Resources).
XSL style sheets contain rules for the transformation from one XML format to another XML format (i.e. any well-formed markup language). These rules are written as so called templates that can be applied to the source XML in two ways. They can either be called by name from other templates, or they can be matched to parts of the source automatically. The transformation is done by an XSL processor.
XSL processors are typically initialized with a reference to the source XML and a reference to the style sheet to be used. As a first step of the transformation, the XSL processor should be given a template that non-ambiguously matches some part of the source. All other templates will be invoked from that template, which usually matches the root node. This is analogous to a "main routine" which invokes all other subroutines.
Listing 9. ShowWeek.xsl (V.1): XSL template for HTML output of a WebCal week view
<xsl:style sheet>
<xsl:template match="webcal">
<html>
<head>
<title>WebCal - Week</title>
</head>
<body>
<!-- week view content -->
</body>
</html>
</xsl:template>
</xsl:style sheet> |
Including style sheets and calling templates by name
You need a template like this for each view, but the <html>,
<head> and <body> elements will be the same for all the views. So
if these elements were extracted and put in a common template, the template can be called (by
name) from all views.
Listing 10. ShowWeek.xsl (V.2): Including and calling a style sheet that produces the frame
<xsl:style sheet>
<xsl:include href="http://localhost/webcal/html/Frame.xsl"/>
<xsl:template match="webcal">
<xsl:call-template name="frame"/>
</xsl:template>
</xsl:style sheet> |
Given that the content is now generated by the included style sheet, do we still need a style sheet for every view? And where is the actual view content (inside the frame) being generated? The template that generates the frame needs to call another template -- the template that generates the content. But how does the frame know which template that should be (i.e. for which view the frame is generated)? The frame template does not need to know; it just calls a template named "main." The "main" template is defined in a style sheet. This style sheet is included by the style sheet that contains the template matching "webcal." And this is why we still need one style sheet for every view! Here is the complete structure for the week view:
Listing 11. ShowWeek.xsl (V.3)
<xsl:style sheet>
<xsl:output method="html"/> <!-- for XT -->
<xsl:include href="http://localhost/webcal/html/Frame.xsl"/>
<xsl:include href="http://localhost/webcal/html/ShowWeekMain.xsl"/>
<xsl:template match="webcal">
<xsl:call-template name="frame"/>
</xsl:template>
</xsl:style sheet> |
Listing 12. Frame.xsl
<xsl:style sheet>
<xsl:template name="frame">
<html>
<head>
<title>
WebCal -
<xsl:value-of select="/webcal/http-params/param[@name='action']/@value"/>
</title>
</head>
<body>
<!-- do the frame -->
<table>
<xsl:comment>frame content</xsl:comment>
...
<td>
<div style="width: ...; height: ...; ...>
<xsl:call-template name="main">
<xsl:with-param name="width">
</xsl:with-param>
<xsl:with-param name="height">
</xsl:with-param>
</xsl:call-template>
</div>
</td>
<xsl:comment>frame content continued</xsl:comment>
</table>
</body>
</html>
</xsl:template>
</xsl:style sheet> |
Listing 13. ShowWeekMain.xsl
<xsl:style sheet>
<xsl:template match="main">
<xsl:param name="width"/>
<xsl:param name="height"/>
<xsl:comment>Week view content</xsl:comment>
<!-- produce week view content here. Keep in mind this is called from
inside a <div> element with the given width and height -->
</xsl:template>
</xsl:style sheet> |
All this would produce the following HTML from XML data as shown in Listing 4.
Listing 14. HTML for the week view
<html>
<head>
<title>WebCal - ShowWeek</title>
</head>
<body>
<table>
<!--frame content-->
...
<td>
<div style="width: ...; height: ...; ...>
<!--week view content-->
...
</div>
</td>
<!--frame content continued-->
...
</table>
</body>
</html> |
Selecting necessary style sheets
Typically there is no need to have an extra style sheet for a frame if the output format is less complex than HTML, such as WML. Also, views could share style sheets if they display very similar content. In WebCal, the views for creating and editing events use the same style sheet while the source XML is slightly different (see Step 3 for the code).
But in general, the following style sheets are needed when using this framework:
- One root style sheet per view and format (like ShowWeek.xsl above)
- One style sheet for the frame per format
- One style sheet for the view contents per view and format, containing a named template, which is called by the "frame" template
Every style sheet is in its own file. There can be multiple templates in
one style sheet, so the "frame" and "main" templates can apply other templates
to parts of the response XML using <xsl:call-template> or <xsl:apply-templates>.
To be able to use HTTP for including style sheets as shown above, all style sheets need to be under the local Web server document directory, as shown in Listing 15:
Listing 15. The local Web server directory
/
webcal/
html/
Frame.xsl
LoginView.xsl
LoginViewMain.xsl
DayView.xsl
DayViewMain.xsl
WeekView.xsl
WeekViewMain.xsl
...
wml/
Frame.xsl
LoginView.xsl
LoginViewMain.xsl
... |
Doing the transformation in Java
WebCal uses XT from James Clark (see Resources) to apply the style sheets to the response XML. The transformation involves some calls to the XT package, as shown below. Other XSL processors, like LotusXSL (see Resources), handle this differently.
From the HTTP request, WebCal retrieves:
- The browser type
- The format the browser understands
- The language it is set to
- The requested action
From all this, we are able to find the right root XSL style sheet for our view. See Listing 16. XSL transformation in Java.
Summarizing Step 1: Lessons learned
For XML design and XML generation:
- Identify the information your views need.
- Separate XML-generation code written for commonly needed information from XML-generation code written for information specifically needed by views.
- Do complicated computations in Java code before or during XML generation and reflect the result in your XML (if possible and if needed for every response format).
- Keep the whole structure flexible.
For the general structure of the XSL style sheets:
-
The XSL style sheets should be in the document directory of the Web server
to enable loading them with
<xsl:include>.
Step 2: Generating output with XSLT
The basic part of the output, the <html>, <head> and <body> tags, have already been addressed in the previous section. This section
discusses the generation of HTML inside the <body> tag, which part
is done in the XSL for the frame, and which part is done in the various
"main" style sheets.
Tables are a good means of laying out HTML pages. WebCal uses a table for the frame with the main part residing in the largest table cell in the middle of the frame. The red lines in Figure 3 show the table which is used in Frame.xsl to draw the frame. Everything apart from the main section in the middle is done in Frame.xsl. The links on the three navigation panels are defined in the XML data for each view.
Figure 3. Table cells in the layout of the WebCal UI

Using <xsl:apply-templates> and <xsl:for-each> to process XML elements
It is important to know how the XSL style sheet for the frame accesses the XML data. For the links
on the left and the links in the top navigation bar, the <xsl:apply-templates>
instruction can be used. See Listing 17. Generating the navigation bars.
<xsl:apply-templates> applies templates to XML nodes. That
means the XSL processor looks for XML elements that match the expression
defined by the "select" attribute of <xsl:apply-tempates>. In
the case of the side links, all <links> elements under the
<global>
element in the navigation section would be matched. As shown in the XML
code for the week view in Listing
4, there is only one such element. It can have any number of
<link>
elements as children. <xsl:with-param> can be used to pass
any number of named parameters to the matching template. In this case it
passes the name of a style that should be used for the link.
This article doesn't go into styles, images and other techniques to improve the look and feel of Web applications. Take a look at the source code of the sample application to see how to define and use CSS styles with XSL.
The template that matches the <links> element is also defined
in Frame.xsl. It uses <xsl:for-each> to iterate through the
<link>
children of <links>. In the loop, it applies a template matching
the current <link> element (referenced by "." meaning
the current element), passing on the "css" parameter. After each
link, it inserts a <br/> element, so there will be one link per line on the left side.
Listing 18: Ensuring one link per line on the left side
<xsl:template match="links">Â Â <xsl:param name="css"/> Â <xsl:for-each select="link"> Â Â Â <xsl:apply-templates select="."> Â Â Â Â Â <xsl:with-param name="css" select="$css"/> Â Â Â </xsl:apply-templates> Â Â Â <br/> Â </xsl:for-each> </xsl:template> |
You can have two types of links, internal and external (as shown in the XML for the week view (see Listing
4)). The type is defined by the "type" attribute of the <link> element.
For each link type, we can define a template that is automatically matched
to the correct link nodes. XML attributes are referenced by "@"
followed by the attribute name. The expression in square brackets in the
"match" attribute of <xsl:template> must evaluate to a boolean value
meaning whether this template matches the node. External links are
easily generated as shown here for the "home" link:
Listing 19. An external link in XML
<link type="external" href="http://www.ibm.com/developer" text="Home"/> |
Listing 20. XSL template matching external links
<xsl:template match="link[@type='external']">
 <xsl:param name="css"/>
 <a class="{$css}" href="{@href}"><xsl:value-of select="@text"/></a>
</xsl:template>Â
|
Listing 21. HTML after application of the external link template
<a class="..." href="http://www.ibm.com/developer">Home</a> |
Internal links, however, link to the WebCalServet and can have any number
of <pass-param> children that have to be converted to HTTP
parameters. This is a little more complicated and requires some navigating
through the XML data. The following link is taken from the <main-nav>
section of the XML data. It will be displayed on the top navigation bar
and points to the day view of the current date. (The <main-nav>
element is processed by a template similar to that used on the <links>
element.
The only difference is that the links are not separated by
<br/>
elements, but by vertical bar characters.) The date has been passed to
the servlet as an HTTP parameter and is included in the XML in the <http-params>
section.
Listing 22. An internal link from the main nav section of the XML data
<link type="internal" text="Day" href="ShowDay"> Â <pass-param name="date"/> </link> |
Listing 23. XSL template matching internal links
Listing 24. The HTML after XSL processing
<a class="..." href="/webcal/WebCalServlet?action=ShowDay&date=...">Day</a> |
The template matching the <link> element uses an <xsl:variable>
that uses <xsl:apply-templates> to apply one of the two templates
matching <pass-param> elements to all existing <pass-param>
children of the current <link> element. The variable named
"params" then contains the results of those template applications. The first template
matching <pass-param> matches all <pass-param>
elements, the second one matches only those <pass-param> elements
that have a "value" attribute. In XSL, the more specific
rule takes precedence, so the second template matches the <pass-param>
elements that have a "value" attribute.
See the sidebar Template precedence for a reminder of how XSL handles precedence.
The first template uses an XPath expression to look up the value from
the <http-params> section. The expression "/webcal/http-params/param[@name=$pname]/@value"
can be read as: "Give me the value of the attribute named 'value'
of the <param> element under the <http-params>
element under the <webcal> element, whose 'name' attribute
has the value defined in the variable 'pname'." With this value,
the template builds a string like "&name=value". The ampersand
(&) has to be escaped by using the & entity, as in HTML.
A similar expression is used to generate the page title from the action
HTTP parameter in the <head> section (see Listing
12).
The second template just uses the expression @value to refer
to the current element's "value" attribute, where current refers
to the <pass-param> element, which is matched by the template.
From the value and from the "name" attribute, the template, again,
generates a string "&name=value".
In the template matching external links, the variable "params" contains
a concatenation of all strings generated from <pass-param>
elements. That concatenation is then included in the "href" attribute
of the generated <a> element (href="...{$params}").
More about saving results of XPath expressions in XSL variables
The bottom navigation bar of the frame contains some links that are not fixed; they depend on the current view. The bottom navigation bar in the calendar views contains a link that leads to a page where the user can create a new event. Once an event is created, it is displayed in the calendar as a link to an event-details view. In that view, the subnavigation bar contains links for going back, editing the event, and deleting the event. But the look and feel of the subnavigation bar is consistent, so I'd create it in the frame style sheet.
The <navigation> section of the XML data contains information
on the content of the subnavigation bar in the form of <link>
elements for each view. To be able to access that information, the "frame"
template needs to know which view is displayed. The <http-params>
section of the XML data contains the value of the action parameter.
Listing 25 shows how to save the current action and a reference to the
corresponding <action> element in two XSL variables. The reference
to the <action> element is then used to generate the subnavigation
bar.
See the Variables and XPath expressions sidebar for a few more details.
Listing 25. Saving the current action and a reference to its element in two XML variables
<webcal>
<http-params>
<param name="action" value="ShowWeek"/>
...
<navigation>
...
<actions>
...
<action name="ShowWeek">
<link type="internal" text="New Event" href="ShowNewEvent">
<pass-param name="date"/>
</link>
</sub-nav>
</action>
...
</webcal> |
Listing 26. XSL getting the current action name and the corresponding <action> element
The part generating the subnavigation applies a template matching <sub-nav>
elements to the <sub-nav> child of the navigation node corresponding
to the current action. For WebCal, that template looks exactly the same
as the template generating the main navigation bar.
The main panel is generated by a template called "main" that is different
for every view. It is called from within an HTML <div> tag,
which limits the main panel's size, and displays scrollbars if necessary.
The preferred dimensions are passed to the "main" template as named parameters.
In the following, the week view is used as an example of how to transform XML application data to HTML.
Figure 4. Use of nested tables to layout the week view

Listing 27. Calling the "main" template
<xsl:template name="frame">
 ...
 <td class="main" align="left" valign="top" width="{$main_width}" height="{$main_height}">
   <div style="... width:{$main_width}px; height:{$main_height}px; overflow: auto; ...">Â
     <xsl:call-template name="main">
       <xsl:with-param name="width" select="$main_width"/>Â
       <xsl:with-param name="height" select="$main_height"/>
     </xsl:call-template>
   </div>
 </td>
 ...  Â
</xsl:tempate>
|
The variables main_width and main_height are calculated
within the "frame" template. The width depends on the size of
the banner image and the height is arbitrarily set to a number of pixels.
In the "main" templates, techniques similar to those used in
the frame are used to display the view content. Take a look at the Show...Main.xsl
files to see how the pages are laid out. There are a few special XSL features,
though, which I'll explain in the next section.
In the week view, the week is divided into two rows. Since this is for HTML
only (you may not want to use a similar display on other devices), the
division into two rows is done in the XSL style sheet. You
may be tempted to use <xsl:for-each> along with the <xsl:if>
and the position() function as shown in Listing 28. position()
returns the sequence number of the for-each iteration, starting
with 1.
Listing 28. Dividing the week into two rows, attempt 1
<xsl:template name="main"> Â ... Â <table> Â Â Â <tr> Â Â Â Â Â <!-- title --> ... Â Â Â </tr> Â Â Â <tr> Â Â Â Â Â <xsl:for-each select="webcal/week/day"> Â Â Â Â Â Â Â <!-- do the day --> ... Â Â Â Â Â Â Â <xsl:if test="position()=4"> Â Â Â Â Â Â Â Â Â <!-- next row --> Â Â Â Â Â Â Â Â Â </tr> Â Â Â Â Â Â Â Â Â <tr> Â Â Â Â Â Â Â </xsl:if> Â Â Â Â Â </xsl:for-each> Â Â Â </tr> Â </table> </xsl:tempate> |
This does not work in XSL, because XSL style sheets must be well formed.
That means every opening tag must have a corresponding closing tag and
elements cannot be nested partly (wrong: <a><b></a></b>).
The red </tr> tag is intended as a closing tag for the <tr>
tag before <xsl:for-each>. But this would mean the <xsl:for-each>
and <xsl:if> element are partly nested with the <tr>
element. The XML specification forces the XSL processor to interpret the
last </tr> tag as a closing tag for the <tr> tag
just before <xsl:for-each> and the two red tags as errors (a
closing tag without opening tag and an opening tag without closing tag).
One solution to this problem is to enumerate the days in the
XML, then use matching expressions. In WebCal, each day of the week has
an additional attribute named "num," running from "1" to "7". XSL supports boolean expressions for comparing numbers, so I can implement two loops within two <tr> elements, using
<xsl:apply-templates>,
as shown in Listing 29:
Listing 29. Dividing the week into two rows, attempt 2
<xsl:template name="main">
<table>
<tr>
<!-- title --> ...
</tr>
<tr valign="top">
<xsl:apply-templates select="/webcal/week/day
[@num<=4]
"/>
</tr>
<tr valign="top">
<xsl:apply-templates select="/webcal/week/day
[@num>=5]
"/>
</tr>
</table>
</xsl:tempate>
<xsl:tamplate match="day">
<!-- this matches all day elements -->
<!-- do the day here --> ...
</xsl:template> |
The red select criteria for <xsl:apply-templates> read as
@num<=4 and @num>=5. The < and > characters should always be escaped in XSL. All day elements, no matter whether in
the first or second loop, are then processed (that is, matched) by the
"day" template.
Generating the title bars for each day is another problem. The XML
element for a day has an attribute named "date." This is formatted "yyyy-mm-dd" (the
ISO standardized format). So how can you transform this into something
like "day mm-dd"? For the "mm-dd" part, XSL provides
string operations. By using substring-after(), substring-before(),
or combinations of both, you can parse strings.
For the name of the weekday, the "num" attribute can be used
with the <xsl:choose> statement, as shown in Listing 30.
Listing 30. <xsl:choose> and string operations
<xsl:template match="day">
 <table>
   <tr>
     <td class="maininverse"...>
       <xsl:choose>
         <xsl:when test="@num=1">Sun</xsl:when>
         <xsl:when test="@num=2">Mon</xsl:when>
         ...
       </xsl:choose>
     <xsl:value-of select="' '"/><!-- this generates a space -->
       <a class="maininverse" href="/webcal/WebCalServlet?action=ShowDay&date={@date}">
         <xsl:value-of select="substring-after(@date,'-')"/>
       </a>
     </td>    Â
   </tr>
   <!-- process events here --> ...
 </table>
</xsl:template>
|
The string operations also extract event start and end times from the
"start" and "end" attributes of the <event> element.
Summarizing Step 2
Step 2 shows how to transform XML to HTML. Using the techniques shown above, XML data can also be transformed to any other well-formed markup language to support multiple devices. Having an intermediary format that is common to all supported client formats helps separate application logic from presentation logic.
If you need more detailed instructions, The XML Bible (see Resources) gives an excellent overview of XSL and XPath, including number conversions, comparisons and string operations.
This step explains how to use forms with the XSL framework described in Steps 1 and 2. Of course, the precondition is that the client supports forms, but almost all available HTTP-based browsers support forms. This section shows you how to use XSL to generate HTML forms for editing and creating calendar events (for example, meetings and appointments) in WebCal. The example also shows how actions can share a common style sheet.
Form elements may be generated by XSL templates similar to all other HTML elements, including the <form> element, the "action" attribute of which points to the application servlet. For every form there should be an internal action processing the form after the user has submitted
it. A hidden field is used to invoke a specific internal action, as shown
in Listing 31:
Listing 31. ShowEventFormMain.xsl - used to display a new event or an edit event form
<xsl:template name="main">
... Â
 <form method="post" action="/webcal/WebCalServlet">
   <!-- 'edit' is an XSL variable. It is set to 'true' if the action was 'ShowEditEvent'. -->
   <xsl:if test="$edit='true'">
     <input type="hidden" name="action" value="ProcessEditEvent"/>
     <input type="hidden" name="id" value="{/webcal/event/@id}"/>
   </xsl:if>
   <xsl:if test="$edit='false'">
     <input type="hidden" name="action" value="ProcessNewEvent"/>
   </xsl:if>
   ...
   <!-- build the form -->
   ...Â
 </form>
</xsl:template>
|
Within the form you can use all the input elements available to the
client format. WebCal just uses text input fields on the login, registration,
and show/edit event forms. The name of the input fields will be the HTTP
parameters of the POST action invoked upon submission of the form.
They are available to the servlet via the Java API HttpServletRequest.getParameter(String).
For a tip on how to avoid problems with forms processing conflicting with browser Back and Reload buttons, see the Form processing sidebar.
Listing 32. Generating form elements shows how XSL templates generate the HTML input fields and the submit button.
This article has shown a way of using XML and XSL transformations to create extensible Web applications. Using an intermediary format for application data (thus separating application logic from the UI) and not hard-coding links and other navigation information makes for high maintainability. Integrating a new view for new functionality requires only some updates of the navigation XML and new "main" style sheets for that view (one for each supported format).
| Description | Name | Size | Download method |
|---|---|---|---|
| WebCal, the sample application | x-abstract-webcal.zip | 943 KB | HTTP |
Information about download methods
- Download the current and previous Java
Development Kits.
- Download the Java Servlet
Development Kit (JSDK).
- If you want to use WebSphere as servlet engine, visit IBM's WebSphere
page. You can also review the servlet
tutorial from WebSphere.
- The XML4J parser from IBM alphaWorks is now available as Apache's Xerces-J Parser.
- Learn more about parsing XML files and building XML documents in the developerWorks'
tutorials:
- XML programming in Java technology, Part 1
- XML programming in Java technology, Part 2
- XML programming in Java technology, Part 3
- Download XT from James
Clark to use for XSL transformations.
- Try an excellent XSLT/XPath crash course given in Chapter
17 of The XML Bible, Second Edition (Chapter 14 in the first edition).
- Try another XSL processor that is fairly easy to use: LotusXSL,
also from IBM alphaWorks.
- Download WebCal, the sample application.

Martin Gerlach is working as a post grad supplemental in the Computer Science Department of the IBM Almaden Research Center. He holds a German diploma degree in Computer Science from the University of Applied Sciences of Hamburg. You can contact Martin at mgerlac@almaden.ibm.com.




