Formatting the Document Header


The stylesheet generates the title of the HTML document by accessing the <title> element within the <header> element of the source XML file. To understand such expressions, you need to take a look at the structure of the <header> element in the source document. The actual file contains a lot of material that isn't actually rendered in the HTML: some of this is in the form of XML comments, some in a more structured <revisiondesc> element. If you are interested in these things, it contains fascinating snippets such as:

  <sitem>1997-03-21 : TB : massive changes on plane flight from Chicago to   Vancouver</sitem>  

(Fascinating for two reasons: first, because I'm sure that Tim Bray would have written that comment differently if he was intending it for a wide audience; second, because it shows that even the authors of the XML specification committed the faux pas of using a private microsyntax within the XML elements, rather than marking up the structure of the entry in the form of three subelements: date, author, and details. This is one of the reasons that regular expression handling in XSLT 2.0 is so valuable . Try sorting these comments first by author, then by date, using XSLT 1.0 alone.)

In abbreviated form, the structure of the XML specification starts like this:

  <spec w3c-doctype="rec">   <header>   <title>Extensible Markup Language (XML) 1.0</title>   <version>1.0 (Second Edition)</version>   <w3c-designation>REC-xml-&iso6.doc.date;</w3c-designation>   <w3c-doctype>W3C Recommendation</w3c-doctype>   <pubdate>   <day>&draft.day;</day>   <month>&draft.month;</month>   <year>&draft.year;</year>   </pubdate>   <publoc>   <loc href=" url">url</loc>   (<loc href="url">XHTML</loc>, <loc href="url">XML</loc>, ...)   </publoc>   <latestloc>   <loc href="    url">    url</loc>   </latestloc>   <prevlocs>   <loc href=" url">    url    </loc>   </prevlocs>   <authlist>   <author role="le">   <name>Tim Bray</name>   <affiliation>Textuality and Netscape</affiliation>   <email href="mailto:tbray@textuality.com">   tbray@textuality.com</email>   </author>    more authors    </authlist>   <abstract>   <p>The Extensible Markup Language (XML) is a subset of SGML   that is completely described in this document...   </p>   </abstract>   <status>   <p>This document has been reviewed by W3C Members and   other interested parties ...</p>   <p>This document specifies a syntax... It is a product of the W3C   XML Activity, details of which can be found at <loc href=' url'>    url    </loc>.   <phrase diff="add"><loc role="erratumref" href="http://www.w3.org/XML/xml-   19980210-errata#E100">[E100]</loc> A list of current W3C Recommendations ...   can be found at <loc href='    url    '>    url    </loc>.</p>   <p>This specification uses the term URI, which is defined by   <bibref ref=''Berners-Lee"/>, a work in progress expected to update   <bibref ref="RFC1738"/> and <bibref ref="RFC1808''/>. </p>   </status>   </header>   <body>    main section of document    </body>   <back>    appendices    </back>   </spec>  

Note that some of the tags are structural elements with predictable nesting, while others such as <loc> can appear in all sorts of places, including inline within the text.

The next few template rules are all concerned with processing this header:

  <!-- header: metadata about the spec -->   <!-- pull out information into standard W3C layout -->   <xsl:template match=''header''>   <div class="head">   <xsl:if test= "not (/spec/@role='editors-copy')">   <p>   <a href="http://www.w3.org/">   <img src="http://www.w3.org/Icons/w3c_home"   alt="W3C" height="48" width="72"/>   </a>   </P>   </xsl:if>   <xsl:text>&#10;</xsl:text>   <h1>   <xsl:call-template name="anchor">   <xsl:with-param name="node" select="title[1]"/>   <xsl:with-param name="conditional" select="0"/>   <xsl:with-param name="default.id" select="'title'"/>   </xsl:call-template>   <xsl:apply-templates select="title"/>   <xsl:if test="version">   <xsl:text> </xsl:text>   <xsl:apply-templates select="version"/>   </xsl:if>   </h1>   <xsl:if test="subtitle">   <xsl:text>&#10;</xsl:text>   <h2>   <xsl:call-template name="anchor">   <xsl:with-param name="node" select="subtitle[1]"/>   <xsl:with-param name="conditional" select="0"/>   <xsl:with-param name="default.id" select="'subtitle'"/>   </xsl:call-template>   <xsl:apply-templates select="subtitle"/>   </h2>   </xsl:if>   <xsl:text>&#10;</xsl:text>   <h2>   <xsl:call-template name="anchor">   <xsl:with-param name="node" select="w3c-doctype[1]"/>   <xsl:with-param name="conditional" select="0"/>   <xsl:with-param name="default.id" select="'w3c-doctype'"/>   </xsl:call-template>   <xsl:apply-templates select="w3c-doctype"/>   <xsl:text> </xsl:text>   <xsl:if test="pubdate/day">   <xsl:apply-templates select="pubdate/day"/>   <xsl:text> </xsl:text>   </xsl:if>   <xsl:apply-templates select="pubdate/month"/>   <xsl:text>   </xsl:text>   <xsl:apply-templates select="pubdate/year"/>   </h2>   <dl>   <xsl:apply-templates select="publoc"/>   <xsl:apply-templates select="latestloc"/>   <xsl:apply-templates select="prevlocs"/>   <xsl:apply-templates select="authlist"/>   </dl>   <!-- output the errataloc and altlocs -->   <xsl:apply-templates select="errataloc"/>   <xsl:apply-templates select="preverrataloc"/>   <xsl:apply-templates select="translationloc"/>   <xsl:apply-templates select="altlocs"/>   <xsl:choose>   <xsl:when test="copyright">   <xsl:apply-templates select="copyright"/>   </xsl:when>   <xsl:otherwise>   <p class="copyright">   <a href="http://www.w3.org/Consortium/Legal/ipr-notice#Copyright">   <xsl:text>Copyright</xsl:text>   </a>   <xsl:text>&#xa0;&#xa9;&#xa0;</xsl:text>   <xsl:apply-templates select="pubdate/year"/>   <xsl:text>&#xa0;</xsl:text>   <a href="http://www.w3.org/">   <acronym title="World Wide Web Consortium">W3C</acronym>   </a>   <sup>&#xae;</sup>   <xsl:text> (</xsl:text>   <a href="http://www.lcs.mit.edu/">   <acronym title="Massachusetts Institute of Technology">   MIT</acronym>   </a>   <xsl:text>, </xsl:text>   <a href="http://www.ercim.org/">   <acronym title="European Research Consortium   for Informatics and Mathematics">ERCIM</acronym>   </a>   <xsl:text>( </xsl:text>   <a href="http://www.keio.ac.jp/">Keio</a>   <xsl:text>), All Rights Reserved. W3C </xsl:text>   <a   href="http://www.w3.org/Consortium/Legal/ipr-notice#Legal_Disclaimer">   liability</a>   <xsl:text>, </xsl:text>   <a href="http://www.w3.org/Consortium/Legal/ipr-notice#W3C_Trademarks">   trademark</a>   <xsl:text>, </xsl:text>   <a   href="http://www.w3.org/Consortium/Legal/copyright-documents">   document use</a>   <xsl:text> and </xsl:text>   <a   href="http://www.w3.org/Consortium/Legal/copyright-software">   software licensing</a>   <xsl:text> rules apply.</xsl:text>   </p>   </xsl:otherwise>   </xsl:choose>   </div>   <hr/>   <xsl:apply-templates select="notice"/>   <xsl:apply-templates select="abstract"/>   <xsl:apply-templates select="status"/>   <xsl:apply-templates select="revisiondesc"/>   </xsl:template>  

There's nothing especially complicated here, but the code is worth reading. Note that the template rule controls the ordering of items in the result document (for example, the abstract will always precede the status section, regardless of which comes first in the source XML). However, the formatting of each subsection is delegated to a template rule for that particular element. This is therefore a blend of the navigational and rule-based design patterns. The generation of HTML anchors is also delegated, this time to a named template with parameters. The template looks like this:

  <xsl:template name="anchor">   <xsl:param name="node" select="."/>   <xsl:param name="conditional" select="1"/>   <xsl:param name="default.id" select="''"/>   <xsl:variable name="id">   <xsl:call-template name="object.id">   <xsl:with-param name="node" select="$node"/>   <xsl:with-param name="default.id" select="$default.id"/>   </xsl:call-template>   </xsl:variable>   <xsl:if test="$conditional = 0 or $node/@id">   <a name="{$id}" id="{$id}"/>   </xsl:if>   </xsl:template>  

which in turn calls:

  <xsl:template name="object.id">   <xsl:param name="node" select="."/>   <xsl:param name="default.id" select="''"/>   <xsl:choose>   <!-- can't use the default ID if it's used somewhere else in the   document! -->   <xsl:when test="$default.id != '' and not(key('ids', $default.id))">   <xsl:value-of select="$default.id"/>   </xsl:when>   <xsl:when test="$node/@id">   <xsl:value-of select="$node/@id"/>   </xsl:when>   <xsl:otherwise>   <xsl:value-of select="generate-id($node)"/>   </xsl:otherwise>   </xsl:choose>   </xsl:template>  

The anchor template generates an element of the form <a name="NNN" id="NNN"> . Generating both attributes helps to ensure maximum portability across different browser versions. If the parameter $conditional is set to «1 » , the template does nothing (actually, it computes an ID value and then ignores it: an example where lazy evaluation will produce performance savings). The actual ID value is taken either from the @id attribute of the node passed as a parameter (which defaults to the context node), or from the $default-id parameter. Surprisingly, the $default-id parameter overrides the @id attribute, provided that it is indeed a unique identifier within the source document.

It's instructive to see how much easier this would all be with XSLT 2.0. We could start by rewriting the object.id template as a function:

  <xsl:function name="f:object.id" as="xs:string">   <xsl:param name="node" as="node()"/>   <xsl:param name="default.id" as="xs:string"/>   <xsl:sequence select="   if ($default.id != " and not($node/key('ids', $default.id))   then $default.id   else if ($node/@id)   then $node/@id"/>   else generate-id($node)"/>   </xsl:function>  

If you prefer, the conditional expression in <xsl:sequence> could be written more concisely as:

  select="($default.id[. != '' and not($node/key('ids',.))],   $node/@id,   generate-id($node))[1]"  

The anchor template can also be turned into a function:

  <xsl:function name="f:anchor">   <xsl:param name="node" as="node()"/>   <xsl:param name="conditional" as="xs:boolean"/>   <xsl:param name="default.id" as="xs:string"/>   <xsl:variable name="id" select="f:object.id($node, $default-id)"/>   <xsl:if test="$conditional = 0 or $node/@id">   <a name="{$id}" id="{$id}"/>   </xsl:if>   </xsl:function>  

and a call on this template, previously written as:

  <xsl:call-template name="anchor">   <xsl:with-param name="node" select="w3c-doctype[1]"/>   <xsl:with-param name="conditional" select="0"/>   <xsl:with-param name="default.id" select="'w3c-doctype'"/>   </xsl:call-template>  

can now be rewritten as:

  <xsl:sequence select="f:anchor(w3c-doctype[1], false(), 'w3c-doctype')"/>  

Apart from reducing the size of the two templates from 14/15 lines to 10 lines or less, the size of the call is reduced from 5 lines to 1, and since the anchor template is called 18 times in the stylesheet, this reduces the total size of the stylesheet by 82 lines. (I hope your productivity is not measured by the number of lines of XSLT code that you produce.) Some people argue that verbosity is not a problem in itself, but in my view, if you can see the whole of a template or function on the screen at one time, you are likely to understand its logic more quickly and to make fewer mistakes when you modify it.

The only thing you lose by doing this conversion is the ability of the templates to have default parameters. But I'm not entirely sure this is a bad thing: certainly , it's a feature that many languages don't provide.




XSLT 2.0 Programmer's Reference
NetBeansв„ў IDE Field Guide: Developing Desktop, Web, Enterprise, and Mobile Applications (2nd Edition)
ISBN: 764569090
EAN: 2147483647
Year: 2003
Pages: 324

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net