In many cases, prototypes of the planned web pages already exist and we want to "put the data into them". In these cases, the use of rule-based XSLT is hardly appropriate, and it is better to use XSLT in a procedural style.
The first step is to map the nodes from the XML schemas to the web page elements. During this step we can also make sure that all vital information is present in the web page.
Frequently, a web page does not exactly match an XML document type:
The web page may not contain all the data of an XML document type;
The web page may combine data from several XML document types, as shown in the following example.
Let us assume that a prototype as shown on the right already exists, and that we want to map the web page elements to XML nodes from the schemas shown on the left.
As far as the data from the album
schema is concerned, the
mapping from XML to HTML is straightforward. We simply put the whole HTML
structure into an XSLT root template, and replace the example data elements
with xsl:value-of
instructions specifying the corresponding node
in the album
instance – a simple fill-in-the-blanks technique. In
cases where an element has minOccurs
and maxOccurs
settings other than "1", we enclose it (and its
decoration) in an xsl:for-each
block. Other HTML elements that
depend on the existence of XML nodes are enclosed into an xsl:if
block.
Here is the HTML source code for our prototype as generated by the HTML editor:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta http-equiv="Content-Language" content="en-us"> <meta name="GENERATOR" content="Microsoft FrontPage 4.0"> <meta name="ProgId" content="FrontPage.Editor.Document"> <title></title> </head>
<body bgcolor="#000000" link="#FFFFCC" vlink="#C0C0C0" > <table> <tr font color="#FFFFCC"> <td colspan="2" align="right"> <a href="???">Musicians</a> <a href="???">Bands</a> </td> </tr> <tr> <td> <table> <tr bgcolor="silver"> <td bgcolor="#FFFFCC"> <h2>Blues House Jam</h2> </td> <td rowspan="4"> <img src="post-election-jam.jpg" alt="Blues House Jam"> </td> </tr> <tr> <td bgcolor="#FFFFCC" valign="top"> <p>recorded at the <a href="???"> <img border="0" src="arrow.gif"> </a>Post-Election-Jam</p> <p>October 21, 1947<br> Whitehouse</p> <p><a href="???"><img border="0" src="arrow.gif"></a> Dizzy Gillespie<br> </td> </tr> <tr> <td bgcolor="#FFFFCC"> Publisher:<br> ProductNo: BGJ-47 </td> </tr> </table> </td> </tr> <tr> <td><h3><br> <font color="#C0C0C0">Tracks</font></h3> <table width="100%"> <tr> <td bgcolor="#FFFFCC">1-Post Election Jam I</td> <td align="Right" bgcolor="#FFFFCC">19:35</td> </tr> </table> </td> </tr> <tr> <td><h3><br> <font color="#C0C0C0">Reviews</font></h3> <table width="100%"> <tr> <td bgcolor="#FFFFCC"> <a href="???"><img border="0" src="arrow.gif"> </a>Glenn Astarita - March 21, 2001</td> </tr> </table> </td> </tr> </table><br> </body> </html>
However, most HTML editors produce HTML which, in contrast to XHTML, is
not well-formed XML. This requires a few fixes to the source code. Empty
elements such as <br>
and <img ... >
must
be properly closed with a slash (<br/>
and <img ...
/>
). Also, an entity reference such as
must
be replaced by a valid XML entity ( 
) or by
<xsl:text> </xsl:text>
.
The stylesheet that we create from the HTML prototype must also contain
logic to join the album
data with collaboration
and
jazzMusician
data. We do this with the help of the XPath function
document()
, as explained in the chapter
From
Conceptual Model to Schema::Constraints Across
Documents. We read the corresponding
collaboration
and jazzMusician
documents into XSLT
variables. The following code extracts the information that we want to display
on the web page, such as the name of a collaboration, the date and location of
a performance (when the collaboration is a jam session), etc. From
jazzMusician
documents we extract the first name, middle name, and
last name.
This data is also used to generate link URLs to the corresponding
collaboration
and album
documents. When the user
clicks on these links, the user leaves the album
web page and
moves to a collaboration
or jazzMusician
web page.
These web pages are also dynamically generated: the link consists of a URL to
Tamino with a query part identifying the respective
document in the database, plus an appropriate stylesheet to be processed by
Tamino's pass-thru servlet.
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns="http://www.softwareag.com/tamino/doc/examples/models/jazz/encyclopedia" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > <xsl:output method="html" indent="yes"/> <!-- define a constant for the tamino query string --> <xsl:variable name="query"> http://localhost/servlets/com.softwareag.tamino.api.servlet.TaminoFilter/tamino/jazz/encyclopedia?_XQL= </xsl:variable> <!-- define constant for pass-thru string --> <xsl:variable name="sheet">&_xslsrc=xsl:stylesheet/</xsl:variable> <!-- define constant for encyclopedia collection --> <xsl:variable name="ency">http://localhost/tamino/jazz/encyclopedia</xsl:variable> <!-- Just a single rule for the root node --> <xsl:template match="/"> <!-- Generate HTML document root --> <html> <head/> <body bgcolor="#000000" link="#FFFFCC" vlink="#C0C0C0" > <!-- Top level loop. Remember that we get raw Tamino output. --> <xsl:for-each select="//album"> <!-- Perform a join for the collaboration --> <xsl:variable name="c_query" select= "concat($query,'collaboration[result/@albumNo="',@albumNo,'"]')"/> <xsl:variable name="collab" select="document($c_query)//collaboration"/> <table> <tr> <td colspan="2" align="right"> <font color="#FFFFCC"> <a href= "{concat($query,'jazzMusician',$sheet,'jazzMusician-index.xsl')}" Musicians</a> <a href= "{concat($query,'collaboration[@type="band"]',$sheet,'band-index.xsl')}" Bands</a> </font> </td> </tr> <tr> <td> <table> <tr bgcolor="silver"> <td bgcolor="#FFFFCC"> <h2><xsl:value-of select="title"/></h2> </td> <xsl:if test="coverImage"> <td rowspan="4"> <img src="{concat($ency,'/images/',coverImage)}" alt="{title}"/> </td> </xsl:if> </tr> <tr> <td bgcolor="#FFFFCC" valign="top"> <xsl:choose> <!-- special treatment for jam sessions --> <xsl:when test="$collab/@type='jamSession'"> <p>recorded at the <xsl:value-of select="$collab/name"/></p> <p> <!-- call the template for date formatting --> <xsl:call-template name="format-date"> <xsl:with-param name="date" select="$collab/performedAt/time"/> </xsl:call-template> <br/> <xsl:value-of select= "$collab/performedAt/location"/> </p> </xsl:when> <!-- otherwise print the band/project name --> <xsl:otherwise> <h4> <!-- link includes specification of style sheet --> <a href= "{concat($c_query,$sheet,'collaboration.xsl')}"> <img border="0" src="{concat($ency,'/images/arrow.gif')}"/> </a> <xsl:value-of select="$collab/name"/> </h4> </xsl:otherwise> </xsl:choose> <p> <!-- Loop over all collaborateurs --> <xsl:for-each select="$collab/jazzMusician"> <!-- Perform the join for the jazzMusicians --> <xsl:variable name="m_query" select= "concat($query,'jazzMusician[@ID="',@ID,'"]')"/> <xsl:variable name="musician" select= "document($m_query)//jazzMusician"/> <!-- Create link to jazz musician web page --> <a href= "{concat($m_query,$sheet,'jazzMusician.xsl')}"> <img border="0" src="{concat($ency,'/images/arrow.gif')}"/> </a> <xsl:text> </xsl:text> <xsl:value-of select="$musician/name/first"/> <xsl:text> </xsl:text> <xsl:value-of select="$musician/name/middle"/> <xsl:value-of select="$musician/name/last"/> <br/> </xsl:for-each> </p> </td> </tr> <tr> <td bgcolor="#FFFFCC"> <xsl:if test="publisher"> Publisher: <xsl:value-of select="publisher"/><br/> </xsl:if> ProductNo: <xsl:value-of select="@albumNo"/> </td> </tr> </table> </td> </tr> <tr> <td><h3><br/> <font color="#C0C0C0">Tracks</font></h3> <table width="100%"> <xsl:for-each select="track"> <tr> <td bgcolor="#FFFFCC"> <!-- Print track number --> <xsl:number value="position()" format="1-"/> <!-- Print character content of track element --> <xsl:value-of select="title"/> </td> <td align="Right" bgcolor="#FFFFCC"> <xsl:value-of select= "substring-before(substring-after(duration,'T'),'M')"/>: <xsl:value-of select= "substring-before(substring-after(duration,'M'),'S')"/> </td> </tr> </xsl:for-each> </table> </td> </tr> <!-- Perform the join for the reviews --> <xsl:variable name="r_query" select= "concat($query,'review[album/@albumNo="',@albumNo,'"]')"/> <xsl:variable name="reviews" select="document($r_query)//review"/> <xsl:if test="$reviews"> <tr> <td><h3><br/> <font color="#C0C0C0">Reviews</font></h3> <table width="100%"> <xsl:for-each select="$reviews"> <tr> <td bgcolor="#FFFFCC"> <!-- Create link to review web page --> <a href="{@URL}"> <img border="0" src="{concat($ency,'/images/arrow.gif')}"/> </a> <!-- Perform the join for the critic --> <xsl:variable name="cr_query" select= "concat($query,'critic[@ID="',critic/@ID,'"]')"/> <xsl:variable name="critic" select="document($cr_query)//critic"/> <xsl:value-of select="$critic/name/first"/> <xsl:value-of select="$critic/name/last"/> - <xsl:call-template name="format-date"> <xsl:with-param name="date" select="pubDate"/> </xsl:call-template> </td> </tr> </xsl:for-each> </table> </td> </tr> </xsl:if> </table><br/> </xsl:for-each> </body> </html> </xsl:template> <!-- Date formatting --> <xsl:template name="format-date"> <xsl:param name="date"/> <!-- Get month and convert into name --> <xsl:variable name="month" select="substring($date,6,2)"/> <xsl:choose> <xsl:when test="$month=1">January</xsl:when> <xsl:when test="$month=2">February</xsl:when> <xsl:when test="$month=3">March</xsl:when> <xsl:when test="$month=4">April</xsl:when> <xsl:when test="$month=5">May</xsl:when> <xsl:when test="$month=6">June</xsl:when> <xsl:when test="$month=7">July</xsl:when> <xsl:when test="$month=8">August</xsl:when> <xsl:when test="$month=9">September</xsl:when> <xsl:when test="$month=10">October</xsl:when> <xsl:when test="$month=11">November</xsl:when> <xsl:otherwise>December</xsl:otherwise> </xsl:choose> <xsl:text> </xsl:text> <!-- Get day --> <xsl:value-of select="substring($date,9,2)"/>, <!-- Get year --> <xsl:value-of select="substring($date,1,4)"/> </xsl:template> </xsl:stylesheet>
In this example we see also some advanced formatting. Because XSLT was
designed before XML Schema, it is not aware of XML Schema's built-in datatypes.
Consequently, there are no easy-to-use formatting routines for these datatypes.
This means that if we want to display, for example, a date in any format other
than the standard ISO format, we have to write the necessary formatting routine
ourselves. This is done in the template format-date
.