A Mobile Window on our Portal
In the previous Style Matters column, we saw that XML-encoded documents used for Internet/extranet/intranet portals give us the benefit of presentation independence. The same XML document can be displayed on a desktop browser and on a digital cellular phone browser using two different XSLT sheets. As you know, desktop browsers render HTML documents and digital cellular phone browsers render WML documents. Thus, the same XML document may be transformed into HTML with one XSLT transformation sheet and into WML with another.
In fact, we should mention here that not all digital cellular phone browsers are able to render WML documents -- a lot of them are only able to render HDML documents. HDML is an SGML-based language, and could be considered the ancestor of WML. This week, we'll only talk about WML rendering and keep HDML for the next Style Matters column.
The equipment you'll need for this week's lab can be obtained from http://www.phone.com/developers/index.html. From there, you'll be able to get a WML browser emulator. You'll also need a local HTTP server.
A Brief Introduction to WML
A WML document uses the XML document character set -- currently the Universal Character Set of ISO/IEC-10646 (Unicode 2.0) -- and supports any proper subset of the Unicode character set (for example, US-ASCII, ISO-8859-1, or UTF-8). All WML documents should have a doctype declaration in the document's prolog. So, a WML document should start with
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD wml 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
As can be seen from the doctype declaration, the WML document's root
element is the <wml> element. Be cautious with
uppercase and lowercase handling; we are in XML lands and XML parsers
are case sensitive. So, the <wml> element's name
is to be written in lower case characters. The <wml>
element contains <card> elements:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD wml 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card>
...
</card>
<card>
...
</card>
</wml>
In contrast to HTML documents, which are based on a single scrollable page, WML documents are a collection of pages, known as cards. A WML document is a collection of cards--this collection is referred to as a deck. We should keep in mind that most WML browser screens are limited to four lines of 12 characters. So a card will be rendered, most of the time, in a small screen. This small screen is also scrollable in most implementations. You can think of a card as being simply an interaction activity with the user. Something like, "select an item," "read text," or "enter data." If a card is too big to fit on a device's screen, then the card's content may scroll, or it may be split into a series of screens.
The <card> element can contain several types of
child elements, such as
<onevent><timer><do><a><fieldset><img><input><select><p>
Several of these elements, like the <a>, <input>,
and <select> elements, are also part of the HTML
vocabulary. Some browsers, like Internet Explorer, may even render WML
documents because of the fact that both languages share the same
constructs. Try this yourself by simply changing the file extension
from ".wml" to ".html" and then see Internet
Explorer rendering the elements common to both languages.
Some of these elements have to be in a specific order. Thus the
content of a <card> element should respect a
certain order for its children elements:
<onevent><timer><do>
The <onevent> is to be the first, the <timer>
element the second, and so forth. All the other elements will be
rendered in the order in which you specify them.
Mapping our Portal to a WML Rendering
To give our portal page a WML rendering, we will use an XSLT style sheet (often called a "transformation sheet"--don't worry, both names refer to the same thing).
The model (portal.xml)
The presentation (portal.wml)
The transformation sheet (portal.xsl)
WML browsers do not like any namespace declarations to be
included in the <wml> root element. Here is the
trick to restrain your XSLT engine from any impulses to include
namespace declarations, especially if you included some namespace
declarations in your style sheet and the source XML document.
<xsl:stylesheet xmlns:xinclude="http://www.w3.org/1999/XML/xinclude" xmlns:xlink="http://www.w3.org/TR/xlink" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xinclude xlink" version="1.0">
The <xsl:stylesheet> element is the root element
for XSLT style sheets. To keep the WML browser happy, we added to the
root element the exclude-result-prefixes
attribute. This tells the XSLT engine to use some self control, and
not include any namespace declarations in the result tree (i.e., the
WML document).
In the last article, we presented an XML document used to model our
portal page. In this XML document, each information unit is enclosed
in a <netfolder> element. This element brings in a
news feed from a web service. The web service accepts URL queries and
return XML documents. We used the <xinclude:include>
element to indicate that external content is to be included in our
portal page.
The XInclude interpreter is an XSLT transformation sheet, which
uses the document() function in an XPath expression to
pull XML content from web services. Other parts of the XPath
expression are used to extract a fragment from the included XML
document. This fragment replaces the <xinclude:include>
element and then is further translated (as is the rest of the
document) into the target rendering language vocabulary set. For
today, the target rendering language is WML. We will use a simplified
version of the last article's portal document.
Each <netfolder> element is transformed into a
display unit. In the case of HTML, we created a portal window for each
<netfolder> element. In the case of WML, each
<netfolder> element is to be transformed into a
card. This is not completely straightforward, as WML cards need to be
referred to with IDs, and referring to external element IDs using
only XSLT is not an easy task. To simplify things, we would need an
XInclude interpreter that merged all the documents prior to any XSLT
processing. By treating the document as a whole, referring to IDs
would be a lot simpler. I instead opted for a short cut so that we'd
have more time for more explanations about the XSLT transformation
sheet.
Not having an XInclude interpreter on hand (I have one in my labs, but unfortunately not yet ready for wider distribution), we will create one with XSLT just to illustrate a way to pull XML content from external sources. This is accomplished by the following template:
<xsl:template match="xinclude:include"> <xsl:apply-templates select="document(@href)/topic-list"/> </xsl:template>
This is our XInclude interpreter. It pulls content from an external
document and applies the templates to the XML tree the document()
function created. This function returns a node list, and the XSLT
engine tries to match templates on this node list.
Now our main goal is to display the news feed headlines, as illustrated by Figure 1.
|
| Figure 1: News feed headlines on mobile browser |
The following XSLT style sheet performs the transformation from information unit to display units.
<xsl:template match="topic[@xlink:type='extended']">
<card>
<xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
<xsl:attribute name="title"><xsl:value-of select="@xlink:title"/></xsl:attribute>
<xsl:apply-templates select="xinclude:include" />
<p>
<em>My portal Headlines</em>
<select name="type" title= "MobilePortal"><br>
<xsl:for-eachselect="topic[@xlink:type='locator']">
<option>
<xsl:attribute name="value"><xsl:value-of
select="@id"/></xsl:attribute>
<xsl:attribute name="onpick">#<xsl:value-of
select="@id"/></xsl:attribute>
<xsl:value-of select="@xlink:title"/>
</option>
</xsl:for-each>
</select>
</p>
</card>
<xsl:apply-templates/>
</xsl:template>
The template matches any <topic> element that
contains an attribute set with the value extended. When
the template matches such element, the XSLT engine includes in the
result tree a <card> element. The <card>
element has two attributes: id and title.
These attributes are created with the <xsl:attribute ...>
element. The values of these attributes are created with the
<xsl:value-of> construct. This last construct is
quite useful for pulling content out of an info set (i.e., the
internal model--after parsing--of an XML document). The select
attribute's values are XPath expressions that extract the value of
the two <topic> attributes: id and
xlink:title.
We then insert a <p> element as child of the
<card> element. Inside the <p>
element, we include a widget that allows the user to select a
headline from several options. This is provided by the <select>
element. Do you have a feeling of déjà vu? Of course,
the <select> element is also part of the HTML
vocabulary!
The <select> element's content is created by a
loop, which for each <topic> element having an
attribute xlink:type equal to "locator," the
XSLT engine should create an <option> element. We
apply the same treatment to the <option> element
that we did for the <card> element, and use the
<xsl:attribute> construct to add the value
and name attributes to the <option>
element. The result created by the template is shown in Figure 1.
Finally, when the user selects a headline, its abstract is displayed as a paragraph, as shown in Figure 2.
|
| Figure 2: Display of a story abstract |
The template for the <abstract> element simply
produces a paragraph, represented in WML as it would be in HTML, with
a <p> element. Check out the full
XSL source to see this template. The final
WML should give you a good idea of how it all works.
Endnotes
Digital phones are not only limited by their display capabilities, but also by their memory limitations. So, check the document size produced by your transformation sheets. Most WML browsers impose a limit on the document size. You may have to use XSLT extensions to create several documents from your portal XML document. Cards can be reorganized to fit in documents with a file size below the maximum allowed.
WML is quite similar to HTML, and this reduces the learning curve for those of us accustomed to the HTML vocabulary. The main difficulty is not in learning the WML rendering language, but more in dealing with the screen real estate and memory limitations.
Very useful for processing WML would be an XInclude interpreter to aggregate the XML external contents prior to XLST processing. This would simplify referring to elements by ID a lot. Another tool in my WML toolkit is an XSLT engine able to output more than one document (most XSLT processors have this available as an extension function). This is particularly useful when you have to chunk the content in compiled WML pages that are to be less than 1.4K. (How do you know if the produced page will be below the maximum size limit? Just use a zip compressor on the WML text document, and check the file size. This should give you a good guesstimate if your file is within the browser file size tolerance.)
In the next column, we'll demonstrate how to create an HDML document with a DSSSL transformation sheet. Until then, have fun in your XML lab.