Book HomeJava and XSLTSearch this book

2.3. Another XSLT Example, Using XHTML

Example 2-5 contains XML data from an imaginary scheduling program. A schedule has an owner followed by a list of appointments. Each appointment has a date, start time, end time, subject, location, and optional notes. Needless to say, a true scheduling application probably has a lot more data, such as repeating appointments, alarms, categories, and many other bells and whistles. Assuming that the scheduler stores its data in XML files, we can easily add features later by writing a stylesheet to convert the existing XML files to some new format.

Example 2-5. schedule.xml

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="schedule.xslt"?>
<schedule>
  <owner>
    <name>
      <first>Eric</first>
      <last>Burke</last>
    </name>
  </owner>
  <appointment>
    <when>
      <date month="03" day="15" year="2001"/>
      <startTime hour="09" minute="30"/>
      <endTime hour="10" minute="30"/>
    </when>
    <subject>Interview potential new hire</subject>
    <location>Rm 103</location>
    <note>Ask Bob for an updated resume.</note>
  </appointment>
  <appointment>
    <when>
      <date month="03" day="15" year="2001"/>
      <startTime hour="15" minute="30"/>
      <endTime hour="16" minute="30"/>
    </when>
    <subject>Dr. Appointment</subject>
    <location>1532 Main Street</location>
  </appointment>
  <appointment>
    <when>
      <date month="03" day="16" year="2001"/>
      <startTime hour="11" minute="30"/>
      <endTime hour="12" minute="30"/>
    </when>
    <subject>Lunch w/Boss</subject>
    <location>Pizza Place on First Capitol Drive</location>
  </appointment>
</schedule>

As you can see, the XML document uses both attributes (month="03") and child elements to represent its data. XSLT has the ability to search for and transform both types of data, as well as comments, processing instructions, and text. In our current document, the appointments are stored in chronological order. Later, we will see how to change the sort order using <xsl:sort>.

Unlike the earlier example, the second line of Example 2-5 contains a reference to the XSLT stylesheet:

<?xml-stylesheet type="text/xsl" href="schedule.xslt"?>

This processing instruction is entirely optional. When viewing the XML document in a web browser that supports XSLT, this is the stylesheet that is used. If you apply the stylesheet from the command line or from a server-side process, however, you normally specify both the XML document and the XSLT document as parameters to the processor. Because of this capability, the processing instruction shown does not force that particular stylesheet to be used. From a development perspective, including this line quickly displays your work because you simply load the XML document into a compatible web browser, and the stylesheet is loaded automatically.

NOTE: In this book, the xml-stylesheet processing instruction uses type="text/xsl". However, some processors use type="text/xml", which does not work with Microsoft Internet Explorer. The XSLT specification contains one example, which uses "text/xml".

Figure 2-3 shows the XHTML output from an XSLT transformation of schedule.xml. As you can see, the stylesheet is capable of producing content that does not appear in the original XML data, such as "Subject:". It can also selectively copy element content and attribute values from the XML source to the result tree; nothing requires every piece of data to be copied.

Figure 2-3

Figure 2-3. XHTML output

The XSLT stylesheet that produces this output is shown in Example 2-6. As mentioned previously, XSLT stylesheets must be well-formed XML documents. Once again, we use .xslt as the filename extension, but .xsl is also common. This stylesheet is based on the skeleton document presented in Example 2-4. However, it produces XHTML instead of HTML.

Example 2-6. schedule.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="xml"
      doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
      doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/>
  <!--****************************************************************
      ** "/" template
      *************************************************************-->
  <xsl:template match="/">
    <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
        <title>Schedule</title>
      </head>
      <body>
        <h2 align="center">
          <xsl:value-of select="schedule/owner/name/first"/>
          <xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text>
          <xsl:value-of select="schedule/owner/name/last"/>'s Schedule</h2>
        <xsl:apply-templates select="schedule/appointment"/>
      </body>
    </html>
  </xsl:template>
  <!--***************************************************************
      ** "appointment" template
      ************************************************************-->
  <xsl:template match="appointment">
    <hr/>
    <h3>Appointment</h3>
    <xsl:apply-templates select="when"/>
    <table>
      <tr>
        <td>Subject:</td>
        <td>
          <xsl:value-of select="subject"/>
        </td>
      </tr>
      <tr>
        <td>Location:</td>
        <td>
          <xsl:value-of select="location"/>
        </td>
      </tr>
      <tr>
        <td>Note:</td>
        <td>
          <xsl:value-of select="note"/>
        </td>
      </tr>
    </table>
  </xsl:template>
  <!--****************************************************************
       ** "when" template
       *************************************************************-->
  <xsl:template match="when">
    <p>
      <xsl:value-of select="date/@month"/>
      <xsl:text>/</xsl:text>
      <xsl:value-of select="date/@day"/>
      <xsl:text>/</xsl:text>
      <xsl:value-of select="date/@year"/>
      from
      <xsl:value-of select="startTime/@hour"/>
      <xsl:text>:</xsl:text>
      <xsl:value-of select="startTime/@minute"/>
      until
      <xsl:value-of select="endTime/@hour"/>
      <xsl:text>:</xsl:text>
      <xsl:value-of select="endTime/@minute"/>
    </p>
  </xsl:template>
</xsl:stylesheet>

The first part of this stylesheet should look familiar. The first four lines are typical of just about any stylesheet you will write. Next, the output method is specified as xml because this stylesheet is producing XHTML instead of HTML:

<xsl:output method="xml"
    doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
    doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/>

The <xsl:output> element produces the following XHTML content:

<?xml version="1.0" encoding="UTF-16"?>
<!DOCTYPE html PUBLIC
  "-//W3C//DTD XHTML 1.0 Transitional//EN" 
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Moving on, the first template in the stylesheet matches "/" and outputs the skeleton for the XHTML document. Another requirement for XHTML is the namespace attribute on the <html> element:

<html xmlns="http://www.w3.org/1999/xhtml">

The remainder of schedule.xslt consists of additional templates, each of which matches a particular pattern in the XML input.

NOTE: Because of its XML syntax, XSLT stylesheets can be hard to read. If you prefix each template with a distinctive comment block as shown in Example 2-6, it is fairly easy to see the overall structure of the stylesheet. Without consistent indentation and comments, the markup tends to run together, making the stylesheet much harder to understand and maintain.

The <xsl:text> element is used to insert additional text into the result tree. Although plain text is allowed in XSLT stylesheets, the <xsl:text> element allows more explicit control over whitespace handling. As shown here, a nonbreaking space is inserted into the result tree:


<xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text>

Unfortunately, the following syntax does not work:

<!-- does not work... -->
<xsl:text>&nbsp;</xsl:text>

This is because &nbsp; is not one of the five built-in entities supported by XML. Since XSLT stylesheets are always well-formed XML, the parser complains when &nbsp; is found in the stylesheet. Replacing the first ampersand character with &amp; allows the XML parser to read the stylesheet into memory. The XML parser interprets this entity and sends the following markup to the XSLT processor:

<!-- this is what the XSLT processor sees, after the XML parser
     interprets the &amp; entity -->
<xsl:text disable-output-escaping="yes">&nbsp;</xsl:text>

The second piece of this solution is the disable-output-escaping="yes" attribute. Without this attribute the XSLT processor may attempt to escape the nonbreaking space by converting it into an actual character. This causes many web browsers to display question marks because they cannot interpret the character. Disabling output escaping tells the XSLT processor to pass &nbsp; to the result tree. Web browsers then interpret and display the nonbreaking space properly.

In the final template shown in Example 2-6, you may notice the element <xsl:value-of select="date/@month"/>. The @ character represents an attribute, so in this case the stylesheet is outputting the value of the month attribute on the date element. For this element:

<date month="03" day="15" year="2001"/>,

the value "03" is copied to the result tree.



Library Navigation Links

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