Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Abstracting the interface

Building an adaptable Web app front end with XML and XSL

Martin Gerlach, Software Engineer, IBM Almaden Research Center
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.

Summary:  Using XML to describe parts of a Web app user interface can make it easy to convert the UI for multiple devices via XSL style sheets. The article describes using XML data and XSL style sheets to build the user interface of complex Web applications. A Web calendar sample application demonstrates the basic techniques and concepts. The article also includes more than two dozen code samples that you can easily extend for your specific requirements.

Date:  01 Dec 2000
Level:  Introductory
Also available in:   Japanese

Activity:  5053 views
Comments:  

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.

The problem

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.


The sample application

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
Performance image

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
Performance image

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.

Structuring the XML data

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.

Compute in Java code or XSL?

You have to balance the trade-offs between generating the data in the XML versus generating it via XSL. In general it is better to do the processing in Java and reflect the results in the XML when the XSL computation is quite complicated, such as for grouping days into weeks and generating the and <previous> elements for navigating days, weeks, and months. Also it is better to generate a tag for each day in the month even if there are no events on some days, instead of trying to implement a loop in XSL (which is not trivial). See Step 2 for XSL details.

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.

Generating XML in Java

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).

Structuring XSL style sheets

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.

The frame

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
Performance image

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>

Template precedence

In XSL, templates with more specific matching expressions have precedence. The XSL specification (see Resources) defines all precedence rules.

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.

Complex XPath expressions

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".

Variables and XPath expressions

XPath expressions and references to XSL variables can be used within attributes of XSL elements, for example, within the "match" attribute of or the "select" attribute of <xsl:value-of>, <xsl:apply-templates> etc. They can also be used in attributes of non-XSL elements, like the "href" attribute of <a>. In that case, the expression needs to be put in curly braces: "{/webcal/now}" (the value of the <now> element).

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

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
Performance image

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.

Using numbers

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.


Step 3: Using forms

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

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>

Form processing

Using the "Back" and "Reload" functions of common Web browsers can cause some confusion with form processing. To avoid this, WebCal uses two types of actions: ShowActions (see ShowAction.java) display views using the XSL transformation described in Step 2. ProcessActions (see ProcessAction.java) are invoked upon form submissions and do not display anything, but redirect the client browser to a "ShowAction" using the Java API HttpServletResponse.sendRedirect(String).

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.


Summing up

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).



Download

DescriptionNameSizeDownload method
WebCal, the sample applicationx-abstract-webcal.zip943 KB HTTP

Information about download methods


Resources

About the author

Martin Gerlach

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.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML
ArticleID=11961
ArticleTitle=Abstracting the interface
publish-date=12012000
author1-email=mgerlac@almaden.ibm.com
author1-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Try IBM PureSystems. No charge.

Special offers