This article describes a mechanism for developing application business data and presentation data separately, and then putting them together using a generic XSLT style sheet. The application business data is formatted in XML, while the presentation data can be created with a traditional tool. The presentation data is enhanced with additional attributes that the style sheet then uses to apply presentation details to the actual content. For the creation of the final format, no special programming is necessary, as this process is completed by the XSLT processor.
To get the most out of this article, you should have a basic knowledge of XML and XSLT. See the Resources section for links to tutorials and papers that can serve as an introduction to these topics. All the examples shown here were produced using the Apache Xerces XML parser, version 2.0.1 and the Apache Xalan XSLT processor, version 2.3.1 (see The Apache XML Project in Resources).
For the application architecture, I chose an n-tier architecture as proposed by the Java 2 Enterprise Edition (J2EE), shown in Figure 1.
Figure 1. The n-tier architecture
Here, I am concentrating on tiers 1 and 2. You can refine this architecture if you expect the user input to be processed by a servlet. This servlet calls the application business logic, which communicates with the backend. This backend can be, for example, an Enterprise JavaBean that exists on a separate server on the network. You can assume that all business data is formatted in XML. You then prepare this data for presentation by using a Java Server Page (JSP), and send it back to the client, as shown in Figure 2.
Figure 2. Using a JSP to prepare data for presentation
If you transfer this picture onto the Model-View-Controller (MVC) design pattern, the servlet takes over the role of the controller, the application logic represents the model, and the JSP is the view element. (Admittedly, this allocation is simplified, but it shows the basic fundamentals.)
Preparing the application data for presentation
To benefit from the advantages of creating your application data with XML, you first must transform your data into a presentable format. One common method for doing this is XSLT style sheets. There are two possibilities within the XSL specifications (see also eXtensible Stylesheets Language in Resources). You can:
- Use so-called formatting objects (FOs)
- Create simple XSLT style sheets
FOs typically create binary output formats and are not yet very widely used (even though they are more specialized for editing presentation data). Also, they are hardly supported by common XSL processors and tools. XSLT style sheets, on the other hand, are more commonly used, so I concentrate on them in this article.
XSLT style sheet processing structure
An XSLT style sheet always uses one XML document that serves as its input. This input document is processed, according to the rules in the style sheet, by the XSL processor. This results in a new XML output document, as shown in Figure 3.
Figure 3. Using XSLT style sheets to process XML documents
In most cases, this structure leads to a mix of rules and presentation data in the style sheet. I assume that I have address data in XML, which needs to be transformed into HTML for presentation in a browser. Listing 1 shows the XML input data. Note that the output of an XSLT style sheet processing step is another XML document. HTML is not necessarily well-formed, so you will always produce XHTML here (XHTML must always be well-formed). I will come back to this later.
Listing 1. XML input data
<addressbook>
<address>
<addressee>John Smith</addressee>
<streetaddress>250 18th Ave SE</streetaddress>
<city>Rochester</city>
<state>MN</state>
<postalCode>55902</postalCode>
</address>
<address>
<addressee>Bill Morris</addressee>
<streetaddress>1234 Center Lane NW</streetaddress>
<city>St. Paul</city>
<state>MN</state>
<postalCode>55123</postalCode>
</address>
</addressbook>
|
Listing 2 shows an XSLT style sheet that transforms this data into HTML format. (See Using Apache Xalan for processing XSLT style sheets in Java to view a Java sample program that runs an XSLT style sheet on a given XML document using the Apache Xalan XSLT processor.)
Listing 2. Using an XSLT style sheet to transform data into HTML
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html" indent="yes"/>
<!-- copy all elements that are not matched otherwise -->
<xsl:template match="* | @*">
<xsl:copy><xsl:copy-of select="@*"/><xsl:apply-templates/></xsl:copy>
</xsl:template>
<xsl:template match="addressbook">
<html>
<head><title>My Addressbook</title></head>
<body>
<h1>My Addressbook</h1>
<table border="1">
<thead>
<tr>
<td>Name</td>
<td>Street</td>
<td>City</td>
<td>Postal Code</td>
</tr>
</thead>
<tbody>
<xsl:for-each select="address">
<tr>
<td><xsl:value-of select="addressee"/></td>
<td><xsl:value-of select="streetaddress"/></td>
<td><xsl:value-of select="city"/></td>
<td><xsl:value-of select="postalCode"/></td>
</tr>
</xsl:for-each>
</tbody>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
|
Listing 2 reveals the problem: The style sheet contains information about the transformation of business data and the presentation data itself, which makes use of an HTML editing environment nearly impossible. In addition, the style sheet needs to be replicated for each output format. For example, if the client device is a mobile phone, the presentation data may be formatted in WML instead of HTML.
Separating the presentation data from the style sheet
Let's try to describe the presentation data separately from the style sheet. To represent the association between data and presentation elements, you can define extensions to the HTML tags used. You can then create a style sheet that uses those extensions to create the final output data.
One problem is that an XSLT processor processes only one XML input document, using the style sheet to create one XML output document. (Note that an XML document can be handed to the XSLT processor in various forms: as a file, as a byte stream, or as an actual DOM object.) In this case, however, you want to have two input sources: the application data and the presentation data. You can solve this in two ways:
- With the
document()function in XSL, embed an additional XML file to be used by a style sheet. - Programmatically merge both input sources into one XML document, which brings you back to one input source for the XSLT processor.
Both options are valid. I'll use the second alternative here, which leads to the structure illustrated in Figure 4.
Figure 4. Merging multiple input sources into one XML document
It is important to note here that the presentation data must exist in a well-formed XML format, as required by the XSLT processor. HTML is not well-formed in all cases, however the emerging XHTML standard closes this gap. I won't go into detail on this topic, but just to provide one example, let's look at the <br> element in HTML. Typically, this element is used as an empty element, but it is not closed as required by the XML standard. In well-formed XML, the element must be written as <br /> (though the most common browsers tolerate both usages).
To convert the data into the desired output format, you need to know which presentation element is associated with which data element. You can do this by adding attributes to the HTML elements, which allows the style sheet to process the data binding, as shown below in Listing 3.
Listing 3. Adding attributes to HTML elements
<?xml version="1.0"?>
<combinedelement>
<view>
<html>
<head>
<title>My Addressbook</title>
</head>
<body>
<form method="POST">
<table id="AddressesPanel" dataSrc="addressbook"
rowelement="address">
<tr>
<th>Name</th>
<th>Street</th>
<th>City</th>
<th>Postal Code</th>
</tr>
<tr>
<td><input datafld="addressee" ></input></td>
<td><input datafld="streetaddress"></input></td>
<td><input datafld="city"></input></td>
<td><input datafld="postalCode"></input></td>
</tr>
</table>
<input type="submit" value="Change"/>
</form>
</body>
</html>
</view>
<model>
<addressbook>
<address>
<addressee>John Smith</addressee>
<streetaddress>250 18th Ave SE</streetaddress>
<city>Rochester</city>
<state>MN</state>
<postalCode>55902</postalCode>
</address>
<address>
<addressee>Bill Morris</addressee>
<streetaddress>1234 Center Lane NW</streetaddress>
<city>St. Paul</city>
<state>MN</state>
<postalCode>55123</postalCode>
</address>
</addressbook>
</model>
</combinedelement>
|
Earlier, I mentioned that both input documents are merged into one. An XML document can only have one root element, which is why I have defined a <combinedelement> element as the new root element. Following MVC terminology, I'll add a <view> element for the presentation data and a <model> element for the business data.
In the following code:
<table id="AddressesPanel" dataSrc="addressbook" rowelement="address"> |
the dataSrc attribute determines the element within the <model> element, which must be displayed in the table. The rowelement attribute defines which element serves as the iterator.
Every input element in the table has a datafld attribute as shown below, which indicates the business data element whose value it displays.
<td><input datafld="addressee" ></input></td> <td><input datafld="streetaddress"></input></td> <td><input datafld="city"></input></td> <td><input datafld="postalCode"></input></td> |
You can easily create the presentation data shown here with a tool like WebSphere Studio (see Resources), or any other environment that lets you create HTML pages. The additional attributes must be inserted into the HTML source manually. However, you can still create the basic presentation view visually in the tool. No programming or XSL skills are required to do this. Of course, you can also create the presentation data without the help of any tool at all, if that's what you feel most comfortable with.
The last piece of the puzzle is the XSLT style sheet that creates the final output format. This style sheet can be developed independently of the actual application, since it does not contain any application-specific information. The style sheet shown in Listing 5 is incomplete and only covers processing of an HTML table. However, other HTML elements could be handled in a very similar way.
Listing 5. Using an XSLT style sheet to process an HTML table
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html" indent="yes"/>
<!-- copy all elements which don't match any template -->
<xsl:template match="* | @*">
<xsl:copy><xsl:copy-of select="@*"/><xsl:apply-templates/></xsl:copy>
</xsl:template>
<!-- delete the model element and all its content -->
<xsl:template match="model"/>
<!-- delete the combinedelement element, but not its content -->
<xsl:template match="combinedelement">
<xsl:apply-templates/>
</xsl:template>
<!-- delete the view element, but not its content -->
<xsl:template match="view">
<xsl:apply-templates/>
</xsl:template>
<!-- handle all <tr> elements -->
<xsl:template match="TR | tr">
<xsl:choose>
<!-- no special handling of the table header -->
<xsl:when test="th">
<xsl:apply-templates/>
</xsl:when>
<xsl:otherwise>
<!-- store the name of the rowelement in a variable -->
<!-- in the addressbook sample, this is 'address' -->
<xsl:variable name="rowname">
<xsl:value-of
select="(ancestor::node()[name() = 'table'])/@rowelement"/>
</xsl:variable>
<!-- call the 'processRow' template, passing the rowelement -->
<!-- and a counter -->
<xsl:call-template name="processRow">
<xsl:with-param name="numAddresses">
<xsl:value-of select="count(//*[name() = $rowname])"/>
</xsl:with-param>
<xsl:with-param name="n">1</xsl:with-param>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- the processRow template calls itself recursively -->
<!-- for all rowelements -->
<xsl:template name="processRow">
<xsl:param name="numAddresses"/>
<xsl:param name="n"/>
<!-- done iterating? -->
<xsl:if test="$numAddresses >= $n">
<xsl:copy>
<!-- for all td's -->
<xsl:for-each select="td">
<!-- copy the element content -->
<xsl:copy>
<xsl:copy-of select="@*"/>
<!-- find all elements with a 'datafld' attribute -->
<!-- and save them in a variable for later use -->
<xsl:for-each select="./*[@datafld]">
<xsl:variable name="elname">
<xsl:value-of select="./@datafld"/>
</xsl:variable>
<!-- copy the element, change the 'datafld' -->
<!-- attribute into a 'name' attribute -->
<xsl:copy>
<xsl:copy-of select="(@*)[name() != 'datafld']"/>
<xsl:attribute name="name">
<xsl:value-of select="@datafld"/>
</xsl:attribute>
<!-- retrieve the value of the element -->
<!-- from the model by using the -->
<!-- 'datafld' attribute as a search -->
<!-- argument -->
<xsl:attribute name="value">
<xsl:value-of
select="(//*[name() = $elname])[position() = $n]"/>
</xsl:attribute>
</xsl:copy>
</xsl:for-each>
</xsl:copy>
</xsl:for-each>
<!-- call the template recursively, increase counter -->
<xsl:call-template name="processRow">
<xsl:with-param name="n">
<xsl:value-of select="$n + 1"/>
</xsl:with-param>
<xsl:with-param name="numAddresses">
<xsl:value-of select="$numAddresses"/>
</xsl:with-param>
</xsl:call-template>
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
|
One detail of the Listing 5 style sheet is worth a closer look, because it is useful in many cases. XSLT does not define any mechanism for handling loops, which are needed in cases where the same input element must be processed multiple times to produce the correct output. You can overcome this limitation by defining a template that calls itself recursively. The template passes a variable to itself that serves as a counter and thus defines when the loop is complete.
The solution I've introduced in this article, in which application business data and presentation data are developed separately and then put together by a generic XSLT style sheet, is by no means complete; it only shows the concept. I expect that similar (but complete and robust) solutions will be developed over time.
Generic style sheets like the one shown in Listing 5 can then be made available and reused where applicable. For example, the Organization for the Advancement of Structured Information Standards (OASIS) has launched the Web Services for Interactive Applications initiative (see Resources). This initiative tries to define a component model for visual Web services, also based on the MVC pattern, which will lead to a technique similar to the one presented here.
- Check out Java
2 Platform, Enterprise Edition (J2EE) for the
latest information on J2EE.
- Explore The Apache XML
Project and its commercial-quality,
standards-based XML solutions and feedback from an
implementation perspective.
- Go to The
Apache Xalan XSLT processor home page for
information on Xalan to help you transform your XML
documents into HTML, text, or other XML document
types.
- Read the eXtensible
Stylesheet Language (XSL) page which includes XSL news,
tutorials, articles, and links.
- Go to the eXtensible
HyperText Markup Language (XHTML) site for XHTML
specifications.
- Read Eric van der Vlist's excellent article, Style-free
XSLT Style Sheets on the xml.com Web site.
-
OASIS has launched the Web Services for Interactive Applications initiative, which attempts to define a component model for visual Web services.
- Find more XML resources on the developerWorks
XML technology zone.
- Get Rational Application Developer for WebSphere Software, an easy-to-use, integrated development environment for building, testing, and deploying J2EE applications, including generating XML documents from DTDs and schemas.
- Find out how you can become an IBM Certified Developer in XML and related technologies.

Andre Tost works for IBM's Software Group in Rochester, Minnesota, USA. He has been involved in various object-oriented projects in recent years, mostly in product development for IBM's SanFrancisco and WebSphere Business Components products. He is currently working with IBM's strategic business partners.




