The following diagram describes a revised XSLT-based system for
Web-WAP generation.
The system uses James Clark's xt, with minor modifications to
two of its classes. The modifications are briefly explained below,
and in more detail in our chapter in Professional JSP Programming
(Wrox Press). The code for the chapter (and this presentation) is
downloadable from the Wrox web site.

The main addition to the previous design is the "conversion
module" in the center that converts the result of the query into
something that an XML parser can parse and deliver to the XSLT
processor. Apart from that, the changes that need to be made are as
follows:
Ø The configuration page,
configure.jsp, will show more targets.
Ø Within the stylesheet, a
major addition is the mechanism for running Java methods from
within XSLT. (It is the stylesheet, not a JSP, that calls
qBean.queryResult() in this version of the framework.)
Ø The main bean has minor
additions to make the session and session ID available to the
stylesheet, and to replace the mechanism for controlling the size
of output. The getDef() method is no longer helpful because the
stylesheet will be getting its information from parsed XML nodes
rather than from a Dict.
Ø There are two minor
revisions of classes provided within xt.
The Configuration Page
The configuration page, you will recall, is for a systems
administrator to edit in order to configure and maintain the
system. One way to modify it would be to double the number of
targets available to the user at any given time. This would make
the user responsible for the choice between the system that uses
JSP, and the system that uses XSLT. It seems a better division of
responsibilities to give this task to the system administrator by
providing a single Boolean switch between the two systems. The
assumption is that at any given time, only one of the two systems
will be in use, and that switching between them will be
infrequent.
All the changes are in the "targets" section; the rest of the
page is the same and not repeated here:
boolean sendToXSLNotJSP = false; // the switch, initially set to
do JSP
String[][] responseTargets;
if(!sendToXSLNotJSP)
responseTargets = new String[][]{ // default
targets for a JSP system
{"error",
"/jsp/weather/errorpage.jsp"},
{"AllTable",
"/jsp/weather/xhtml/AllTable.jsp"},
{"AllText",
"/jsp/weather/xhtml/AllText.jsp"},
{"TimeTemp",
"/jsp/weather/xhtml/TimeTemp.jsp"},
{"wml-AllTable",
"/jsp/weather/wml/AllTable.jsp"},
{"wml-AllText",
"/jsp/weather/wml/AllText.jsp"},
{"wml-TimeTemp",
"/jsp/weather/wml/TimeTemp.jsp"}
};
else
responseTargets = new String[][]{ // targets for an
XSLT system
{"error",
"/jsp/weather/errorpage.jsp"},
{"AllTable",
"/xslAllTable/xslrules/weather.xml"},
{"TimeTemp",
"/xslTimeTemp/xslrules/weather.xml"},
{"AllText",
"/xslAllText/xslrules/weather.xml"},
{"wml-AllTable",
"/xslWmlAllTable/xslrules/weather.xml"},
{"wml-AllText",
"/xslWmlAllText/xslrules/weather.xml"},
{"wml-TimeTemp",
"/xslWmlTimeTemp/xslrules/weather.xml"}
};
The new targets indicate that there are six stylesheets in the
xslrules directory: three for XHTML output, and three for WML
output. Also in that directory is an XML file, weather.xml. In a
framework that uses XML more (for configuration, or data
interchange, or both), this file could contain useful information.
In this example, it is simply ignored, as the stylesheet
synthesizes its output from the result of the query.
xslTimeTemp.xsl
The important part of this stylesheet (and the other two
stylesheets) is how Java code gets called. First, in the
declaration part, a special namespace is declared:
xmlns:xqd="http://www.jclark.com/xt/java/MyNa.jspUtil.XmlQueryStringDoc"
The xqd namespace (a mnemonic for XmlQueryDoc) is declared to be
associated with the XmlQueryStringDoc class in the MyNa.jspUtil
package. This is the class that runs the query, converts its
QueryResult to an XML string and passes it on to an XML parser.
This is all done by a static queryResult() method that returns a
NodeIterator object, which is the kind of object that xt expects
from its parser.
We are going to use the queryResult() method within the
stylesheet. Java methods are a particular kind of what are called
'extension functions' in the XSLT recommendation, which says that
although the 1.0 version of the XSLT does not define a standard
mechanism for implementing such extensions, "the XSL WG (working
group) intends to define such a mechanism in a future version of
this specification or in a separate specification." There have been
more recent discussions that indicate that the ways Java extensions
are implemented are very similar in all the major XSLT processors,
so we can expect a standardization effort soon.
In outline, the stylesheet is structured as follows:
<!-- stylesheet declarations -->
<xsl:template match="/">
<!-- matches the root of the
XML document tree -->
<!-- first block of HTML or
WML material to pass through to output -->
<xsl:variable ... />
<!-- declares and initializes
a variable -->
<xsl:choose>
<!--
checks to see if there is output;
if not, outputs a message; otherwise outputs a table
-->
</xsl:choose>
<!-- second block of HTML or
WML material for output -->
</xsl:template>
</xsl:stylesheet>
Here is the stylesheet for WML output, broken into sections. The
first one contains declarations:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xqd="http://www.jclark.com/xt/java/MyNa.jspUtil.XmlQueryStringDoc"
xmlns="http://www.w3.org/TR/xhtml1/strict"
xmlns:javaout="http://www.jclark.com/xt/java"
exclude-result-prefixes="javaout xqd #default">
<xsl:output
method="javaout:MyNa.jspUtil.XMLOutputHandler"
indent="yes"
encoding="UTF-8"
media-type="text/vnd.wap.wml"
omit-xml-declaration="no"
doctype-public="-//PHONE.COM//DTD
WML 1.1//EN"
doctype-system="http://www.phone.com/dtd/wml11.dtd" />
<xsl:param name="theSessionID"
select="NoHttpSessionIDProvided"/>
Next we have the initial template, including the Java function
call:
<xsl:template match="/">
<wml>
<head>
<meta http-equiv="Cache-Control" content="no-cache"
forua="true"/>
</head>
<card
id="output" title="AllTable">
<do type="accept" label="again" >
<go href="#askCard" />
</do>
<xsl:variable name="rows"
select="xqd:query-result($theSessionID)//*[name(.)='row']"
/>
The xsl:choose element is next. For small WAP screens, we format
the output as two columns:
<xsl:choose>
<xsl:when test="count($rows)=0">
<p
mode="nowrap">
Sorry, no weather in your zip-code.
</p>
</xsl:when>
<xsl:otherwise>
<p>
<table columns="2">
<!-- a row for each header -->
<xsl:for-each select="$rows[1]/*" >
<tr>
<td> <xsl:value-of select="@*" /> </td>
<td> <xsl:value-of select="." /> </td>
</tr>
</xsl:for-each>
</table>
</p>
</xsl:otherwise>
</xsl:choose>
</card>
The rest is mostly the entry card in pure WML:
<card
id="askCard" title="Weather">
<do type="accept" label="Go!" >
<go href="weather.jsp">
<postfield name="query" value="$query" />
<postfield name="QP1" value="$QP1" />
<postfield
name="target" value="wml-$(query)" />
</go>
</do>
<p align="center">Weather Page</p>
<p>
Zip?
<input name="QP1" format="*N" maxlength="10" value=""
/><br />
Query?
<select name="query">
<option value="TimeTemp" > time & temp
</option>
<option value="AllTable" > all fields </option>
<option value="AllText" > all fields-format
</option>
</select>
</p>
</card>
</wml>
</xsl:template>
</xsl:stylesheet>