http://www.developer.com/

Back to article

Dynamic Screen Generation With XSL


November 13, 2002

Introduction

One of the capabilities of XSL (eXtensible Stylesheet Language) is to dynamically generate screens from meta data. Rather than code HTML over and over again, a single stylesheet can be used to generate an infinite number of data capture screens. Maintenance of these screens also becomes easier because a change to the common stylesheet will be reflected on all pages.

To demonstrate this concept, we'll build the user interface for a dynamic survey application together. This will provide a real working component that can be extended for your application. The following outline is a roadmap for how we'll cover the topic:

  1. Describe the business problem we would like to solve; that is, creating dynamic pop-up surveys.
  2. Design an XML file representing the survey and its questions.
  3. Build a stylesheet to be able to publish or dynamically generate surveys.
  4. Wrap up by summarizing what we've learned.

The Business Problem

Our business customer would like to add dynamic pop-up surveys to portions of the company site to gain feedback from end users. The customer wants the ability to dynamically present short, frequent surveys, targeted toward certain users as well as some general surveys that apply to all users.

Our customer would like the survey application to support various types of questions whose answers might be captured by any of the following widget types:

  • Drop-down boxes
  • Radio groups
  • Check box groups
  • Text Fields
  • Text Areas

Our customer would like the option of having the question text appear above the question, or to the left of the question. Once a survey has been created, it may be necessary to re-order the questions, or even to insert new questions as the survey results begin to come in.

As our customer is describing the functionality they would like, we realize that XSL can help make generation of the survey screens a snap.

Survey XML

Let's design an XML stream to capture the data we are going to need to present a survey and its questions.

A Survey will contain a number of Question nodes. Each Question will contain a Text node representing the question wording and an AnswerType node representing which type of data capture widget will be used to gather the answer. AnswerType nodes may have multiple Option nodes representing the options the user is allowed to choose from in answering a given question.

Now let's compose a sample XML stream to flesh out the details:

<Survey name="Site Survey" layout="label_side">
  <Question name="q1" seq="1">
    <Text>How often do you visit our site?</Text>
    <AnswerType type="select">
      <Option>Daily</Option>
      <Option>Weekly</Option>
      <Option>Monthly</Option>
    </AnswerType>
  </Question>
  <Question name="q2" seq="2">
    <Text>How do you rate our site?</Text>
    <AnswerType type="radio">
      <Option>Fair</Option>
      <Option>Good</Option>
      <Option>Excellent</Option>
    </AnswerType>
  </Question>
  <Question name="q3" seq="3">
    <Text>What ideas do you have to improve our site?</Text>
    <AnswerType type="text_area"/>
  </Question>
  <Question name="q4" seq="4">
    <Text>What is your e-mail address?</Text>
    <AnswerType type="text_field"/>
  </Question>
  <Question name="q5" seq="5">
    <Text>I use the following languages:</Text>
    <AnswerType type="check_box">
      <Option>Java</Option>
      <Option>C#</Option>
      <Option>XSL</Option>
    </AnswerType>
  </Question>
</Survey>

We begin with our Survey element. Its name attribute represents the survey title. We'll also specify whether the question text will appear above or below the widget through the layout attribute.

Our Survey element will contain from 1 to n Question elements. Each Question will have a mandatory name attribute. This will be the name used in the generated HTML widgets. It will also have a seq attribute that will determine the sequence of questions on the generated screen.

All Question elements will have a Text element representing the text that will appear to the user. The AnswerType element will represent all of the widget types that our customer has asked us for: select, radio, checkbox, text_field, text_area.

The select, radio, and checkbox AnswerType elements can contain from 1 to n Option elements describing the options. Multiple options can be chosen from check box widgets, while only a single option can be chosen from drop-down and radio widgets.

Survey Style Sheet

We've now designed a XML stream that can be used to represent a multitude of surveys. Now, let's build a stylesheet that can present any of these surveys. We'll take a look at the templates in this stylesheet bit by bit beginning with our root template.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl=
     "http://www.w3.org/1999/XSL/Transform" >

<xsl:output method="html" indent="yes"/>

<xsl:template match="/">
  <html>
    <head>
      <title><xsl:value-of select="Survey/@name"/></title>
    </head>
    <body>
      <form action="Survey.jsp">
        <table>
          <xsl:apply-templates select="//Question">
            <xsl:sort select="@seq"/>
          </xsl:apply-templates>
        </table>
        </input type="submit" value="Submit Survey" name="submit"/>
      </form>
    </body>
  </html>
</xsl:template>


The root template builds the shell of the HTML document we are generating. It includes the survey name in the title element of the page. The HTML body includes a form which will be used to submit all of the questions. The form will be posted to Survey.jsp to record the survey results. Note that all of the Question elements are selected via the //Question XPath expression. These nodes are sorted by the seq attribute before matching templates are applied.

Let's take a look at the templates that may match these Question nodes.





<xsl:template match="Question[../@layout = 'label_side']">
  <tr>
    <td>
      <xsl:value-of select="Text"/>
    </td>
    <td>
      <xsl:apply-templates select="AnswerType"/>
    </td>
  </tr>
</xsl:template>

<xsl:template match="Question[../@layout = 'label_top']">
  <tr>
    <td>
      <xsl:value-of select="Text"/>
    </td>
  </tr>
  <tr>
    <td>
      <xsl:apply-templates select="AnswerType"/>
    </td>
  </tr>
</xsl:template>

One of the two templates matching on Question nodes will be invoked depending on whether a label_side or label_top has been specified in the layout attribute of the source document. The Question[../@layout = 'label_side'] XPath expression can be expressed in English as: match this template on Question elements where the parent element (Survey) has a layout attribute equal to label_side.

The Question templates contain the HTML shell of each question. When a label side layout is requested, a single table row will be generated. When a label top layout is requested, two table rows are generated. The Text element is placed inside the table cell representing the question. Templates are applied to AnswerType elements to generate the appropriate widget in its cell.

Now, let's look at the various AnswerType and Option templates.

<xsl:template match="AnswerType[@type = 'text_field']">
  <input type="text" size="40" name="{../@name}"/>
</xsl:template>

<xsl:template match="AnswerType[@type = 'text_area']">
  <textarea name="{../@name}" cols="40" rows="4"/>
</xsl:template>

<xsl:template match="AnswerType[@type = 'select']">
  <select name="{../@name}">
    <xsl:copy-of select="Option"/>
  </select>
</xsl:template>

<xsl:template match="AnswerType[@type = 'radio']">
  <xsl:apply-templates select="Option"/>
</xsl:template>

<xsl:template match="AnswerType[@type = 'radio']/Option">
  <input type="radio" name="{../../@name}" value="{.}"/>
  <xsl:value-of select="."/>
</xsl:template>

<xsl:template match="AnswerType[@type = 'check_box']">
  <xsl:apply-templates select="Option"/>
</xsl:template>

<xsl:template match="AnswerType[@type = 'check_box']/Option">
  <input type="checkbox" name="{../../@name}" value="{.}"/>
  <xsl:value-of select="."/>
</xsl:template>

</xsl:stylesheet>

Each AnswerType template matches a certain type attribute. These templates generate the various HTML widgets required by our business customer.

Let's look at some of the interesting points of these templates. First of all, when selecting values from the source document into the output document, the <xsl:value-of> element is commonly used. However, when trying to select data into output attributes, this technique does not work. The curly bracket syntax, name="{../@name}", is used to extract data from the source document into the output document. Another approach, not used here, is to use <xsl:attribute>.

Notice how the Option elements in the source document are rendered differently for select, radio, and check box elements. There are three different templates that may be invoked for Option nodes.

  • For select widgets, the Option nodes are simply copied from the source document to the output document intact with the <xsl:copy-of select="Option"/> statement.
  • For radio widgets, each Option node becomes a radio button followed by text.
  • For check_box widgets, each Option node becomes a check box followed by text.

Sample Survey Output

When we run our stylesheet against our sample XML stream, we get the following output:

By changing the layout attribute of the Survey tag to be label_top, the output would change as follows:

You can continue to play with our Survey stylesheet capabilities by changing the source XML document as follows:

  • Changing the sequence of the questions by modifying the seq attribute of Question elements
  • Changing the AnswerType type attribute to produce various widget types
  • Adding new Question elements

Summary

XSL can be used to dynamically generate screens. In fact, a single stylesheet can be used to generate a multitude of screens. This radically simplifies development and maintenance. However, it might put you out of a job! Or more likely, this frees up your time to move on to bigger and better things.

We designed the user interface portion of a survey application. First, we designed an XML stream to capture the data for a survey. Then, we built a single stylesheet that can be used to generate a multitude of surveys. We looked at some output variations by tweaking the Survey XML. This could be the start of your own survey application. But the rest is up to you.

Code Examples

To download the example XML stream and stylesheet, click here.

About the Author

Jeff Ryan is an architect for Hartford Financial Services. He has eighteen years of experience designing and developing automated solutions to business problems. His current focus is on Java, XML, and Web Services technology. He may be reached at jryan@thehartford.com.
Other Articles Written by Jeff Ryan

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date