Book HomeJava and XSLTSearch this book

3.3. Combining Multiple Stylesheets

Through template parameters, named templates, and template modes, we have seen how to create more reusable fragments of code that begin to resemble function calls. By combining multiple stylesheets, one can begin to develop libraries of reusable XSLT templates that can dramatically increase productivity.

Productivity gains occur because programmers are not writing the same code over and over for each stylesheet. Reusable code is placed into a single stylesheet and imported or included into other stylesheets. Another advantage of this technique is maintainability. XSLT syntax can get ugly, and modularizing code into small fragments can greatly enhance readability. For example, we have seen several examples related to the list of presidents so far. Since we almost always want to display the name of a president or vice president, name-formatting templates should be broken out into a separate stylesheet. Example 3-7 shows a stylesheet designed for reuse by other stylesheets.

Example 3-7. nameFormatting.xslt

<?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"/>
  <!--
    ** Show a name formatted like: "Burke, Eric Matthew"
    -->
  <xsl:template match="name" mode="lastFirstMiddle">
    <xsl:value-of select="last"/>
    <xsl:text>, </xsl:text>
    <xsl:value-of select="first"/>
    <xsl:for-each select="middle">
      <xsl:text> disable-output-escaping="yes">&amp;nbsp;</xsl:text>
      <xsl:value-of select="."/>
    </xsl:for-each>
  </xsl:template>

  <!--
    ** Show a name formatted like: "Eric Matthew Burke"
    -->
  <xsl:template match="name" mode="firstMiddleLast">
    <xsl:value-of select="first"/>
    <xsl:for-each select="middle">
      <xsl:text> disable-output-escaping="yes">&amp;nbsp;</xsl:text>
      <xsl:value-of select="."/>
    </xsl:for-each>
    <xsl:text> disable-output-escaping="yes">&amp;nbsp;</xsl:text>
    <xsl:value-of select="last"/>
  </xsl:template>
</xsl:stylesheet>

The code in Example 3-7 uses template modes to determine which template is instantiated. Adding additional templates would be simple, and those changes would be available to any stylesheet that included or imported this one. This stylesheet was designed to be reused by other stylesheets, so it does not include a template that matches the root node.

For large web sites, the ability to import or include stylesheets is crucial. It almost goes without saying that every web page on a large site will contain the same navigation bar, footer, and perhaps a common heading region. Standalone stylesheet fragments included by other stylesheets should generate all of these reusable elements. This allows you to modify something like the copyright notice on your page footer in one place, and those changes are reflected across the entire web site without any programming changes.

3.3.1. <xsl:include>

The <xsl:include> element allows one stylesheet to include another. It is only allowed as a top-level element, meaning that <xsl:include> elements are siblings to <xsl:template> elements in the stylesheet structure. The syntax of <xsl:include> is:

<xsl:include href="uri-reference"/>

When a stylesheet includes another, the included stylesheet is effectively inserted in place of the <xsl:include> element. Actually, the children of its <xsl:stylesheet> element are inserted into the including document. It is possible to include many other stylesheets and for those stylesheets to include others.

Inclusion is a relatively simple mechanism because the resulting stylesheet behaves exactly as if you had typed all included elements into the including stylesheet. This can result in problems when two conflicting template rules are included, so you must be careful to plan ahead to avoid any conflicts. When a conflict occurs, the XSLT processor should report an error and halt.

3.3.2. <xsl:import>

Importing (rather than including) a stylesheet adds some intelligence to the process. When conflicts occur, the importing stylesheet takes precedence over any imported stylesheets. Unlike <xsl:include>, <xsl:import> elements must occur before any other element children of <xsl:stylesheet>, as shown here:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <!-- xsl:import must occur before any other top-level elements -->
  <xsl:import href="pageElements.xslt"/>
  <xsl:import href="globalConstants.xslt"/>
  <xsl:output method="html"/>
  <xsl:template match="/">
    <html>
      ...
    </html>
  </xsl:template>
  <!-- but xsl:include can occur anywhere, provided it is a top-level element -->
  <xsl:include href="nameFormatting.xslt"/>
</xsl:stylesheet>

For the purposes of most web sites, the most common usage pattern is for each page to import or include common stylesheet fragments, such as templates to produce page headers, footers, and other reusable elements on a web site. Once a stylesheet has been included or imported, its templates can be used as if they were in the current stylesheet.

The key reason to use <xsl:import> instead of <xsl:include> is to avoid conflicts. If your stylesheet already has a template that matches pageHeader, you will not be able to include pageElements.xslt if it also has that template. On the other hand, you can use <xsl:import>. In this case, your own pageHeader template will take priority over the imported pageHeader.

NOTE: Changing all <xsl:import> elements to <xsl:include> will help identify any naming conflicts you did not know about.



Library Navigation Links

Copyright © 2002 O'Reilly & Associates. All rights reserved.