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 profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

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]

Integrating data at run time with XSLT style sheets

Creating presentation markup using XML, XSLT, and the MVC design pattern

Andre Tost, Senior Technical Staff Member, IBM, Software Group
Andre Tost
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.

Summary:  Many applications now take advantage of XML to format business data. This allows the use of self-describing, tagged data that can be handled on a wide range of platforms and programming languages. Integration between heterogeneous applications is made easier through the use of XML data formats. Web services technology, for example, promotes the use of XML-based message formats for backend application data. However, integrating that data into user output during run time can be a challenge. In this article, Andre Tost describes how data integration can be achieved through the use of XSLT style sheets.

Date:  01 Jul 2002
Level:  Introductory

Activity:  17408 views
Comments:  

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

Application architecture

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
Example of 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
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
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.

Using Apache Xalan for processing XSLT style sheets in Java

If you want to try out some of the examples given in this article, you may consider developing a little Java application that takes advantage of the Apache Xalan XSLT processor. This XSLT engine is based on the Apache Xerces XML parser and supports the Java API for XML Processing (JAXP) version 1.1. The JAXP 1.1 specification defines an interface called javax.xml.transform.Transformer, an instance of which is used by an application to execute the actual transformation. A Transformer instance is created through the javax.xml.transform.TransformerFactory.

The DoTransform   sample class takes two file names as input -- one for the input XML file and one for the file containing the XSLT style sheet.

Note that since the standard Java APIs are used, you could run this code on any XSLT-compliant processing implementation.

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

Extending the HTML elements

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 data binding style sheet

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.


Summary

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.


Resources

About the author

Andre Tost

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.

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 profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

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

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML
ArticleID=12120
ArticleTitle=Integrating data at run time with XSLT style sheets
publish-date=07012002
author1-email=atost@us.ibm.com
author1-email-cc=