Generating Output with XSLT


XSLT is output-neutral. That is, you can generate just about any type of output from a stylesheet, although XML or HTML are the two most common.

Generating HTML with XSLT

One of the most common uses for XSLT is to create HTML or XHTML from a block of XML. This enables rendering of data for use in browsers without requiring two separate outputs.

RSS is becoming a common XML syntax (see Chapter 19 for more on this), and many sites are using it as a syndication mechanism for news, opinion, or feature releases. Listing 8-19 shows the result of an MSN search for XML displayed as RSS. This search normally provides an XSLT stylesheet but I removed it for this example. Most users do not understand and, therefore, cannot use raw RSS. Therefore, applying an XSLT stylesheet to RSS provides users with a friendlier interface (see Figure 8-5) and more information. Listing 8-20 shows the transformation used to create this.

image from book
Figure 8-5

Listing 8-19: A raw RSS feed

image from book
      <?xml version="1.0" encoding="utf-8"?>      <rss version="2.0">        <channel>          <title>MSN Search: xml</title>          <link>http://search.msn.com:80/results.aspx?q=xml</link>          <description>Search results</description>          <copyright>Copyright &#194;&#169; 2006 Microsoft. All rights          reserved. These XML results may not be used, reproduced or          transmitted in any manner or for any purpose other than          rendering MSN Search results within an RSS aggregator for your          personal, non-commercial use. Any other use of these results          requires express written permission from Microsoft Corporation.          By accessing this web page or using these results in any manner          whatsoever, you agree to be bound by the foregoing          restrictions.</copyright>          <item>            <title>XML.com: XML From the Inside Out -- XML development,            XML resources ...</title>            <link>http://www.xml.com/</link>            <description>Community resources and solutions, XML authoring            tools, XML resources, and interactive forums.</description>            <pubDate>30 Jun 06 17:52:00 UTC</pubDate>          </item>          <item>            <title>XML.org</title>            <link>http://www.xml.org/</link>            <description>News, education, and information about the             application in industrial and commercial            settings.</description>            <pubDate>01 Jul 06 16:04:00 UTC</pubDate>          </item>      ...          <item>            <title>XML Developer Center</title>            <link>http://msdn.microsoft.com/xml/</link>            <description>Microsoft's            tutorial, XML specification, samples, and XML support in            Microsoft applications such as Internet            Explorer.</description>            <pubDate>02 Jul 06 11:02:00 UTC</pubDate>          </item>          </channel>      </rss> 
image from book

Listing 8-20: XSLT Transformation for RSS 2.0

image from book
      <?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" version="1.0" encoding="UTF-8" indent="yes"/>        <xsl:template match="/">          <html>             <head>              <title>                <xsl:value-of select="rss/channel/title"/>              </title>              <style type="text/css" media="screen">              body {                font-family: verdana, arial, sans-serif;                font-size: 80%;                line-height: 1.45em;              }              #itemWrapper {}              #itemWrapperHighlight {                background-color: #E0E0E0;              }              #itemBody{}              </style>            </head>            <body>              <xsl:apply-templates/>            </body>          </html>          </xsl:template>          <xsl:template match="channel">          <h1>            <xsl:value-of select="title"/>          </h1>          <div >            <xsl:value-of select="description"/>            <br/>            <br/>            RSS (or Really Simple Syndication) is the name for a format            used to share information feeds for updating content. <br/>            These feeds contain content from Web sites and contain article headlines,            summaries and links back to full-text articles on the web.<br/>            For more information on RSS see <a      href="http://en.wikipedia.org/wiki/RSS_(protocol)">this page</a>          </div>          <div >            <xsl:apply-templates select="item">              <xsl:with-param name="maxItems" select="6"/>            </xsl:apply-templates>          </div>          </xsl:template>          <xsl:template match="item">          <xsl:param name="maxItems"/>          <xsl:if test="count(preceding::item) < $maxItems">            <div >              <xsl:if test="position() mod 2">                <xsl:attribute name="id">itemWrapperHighlight</xsl:attribute>              </xsl:if>               <h3 >                <xsl:value-of select="title"/>              </h3>              <div >                <xsl:value-of select="description"/>                <br/>                <a>                  <xsl:attribute name="href">                    <xsl:value-of select="url"/>                  </xsl:attribute>                  <xsl:attribute name="alt">                    <xsl:value-of select="title"/>                  </xsl:attribute>            Read more of this item              </a>              </div>            </div>          </xsl:if>        </xsl:template>       </xsl:stylesheet> 
image from book

The code consists of three templates, one each for the root (/), channel, and item nodes.

The root node template begins the HTML page and includes information for the head of the document, including the page title and stylesheet information. It then calls the apply-templates expression. Remember that excluding the select parameter causes all other templates to be called. In this case, selecting the channel node explicitly produces the same effect.

The channel node template is fairly basic: It extracts a few items from the XML and supplements this with additional text. It is worth noting, however, that with-param is used in the call to apply-templates. This defines the maximum number of items to display from the feed. You can experiment changing this value to see how it affects the resulting page.

Most of the complexity in the sample is in the item template. The maxItems parameter is provided in the call to apply the item template. However, this parameter is not available unless a matching param element is included. The test in the conditional if statement <xsl:if test=“count(preceding::item) &lt; $maxItems” > translates to, "Count the preceding calls to the item template. If this value is less than the value of the maxItems parameter, process the contents of this if element." This is a simple means of controlling the number of items displayed from the feed. The third thing to note about the item node template is the if element “<xsl:if test=” position() mod 2 “>”. This test is true (that is, non-zero) for odd-numbered items, and false for even-numbered items. When true, the id of the itemWrapper div changes to itemWrapperHighlight. This style includes a light grey background in the example. The final noteworthy item in the item template is the technique for adding attributes based on the XML content. The attribute element retrieves the desired item using the value-of element, and creates an attribute, in this case the href and alt attributes for the anchor tag.

You can add an XSLT stylesheet to an XML file using the xml-stylesheet processing instruction at the beginning of the XML file (after the XML declaration):

      <?xml-stylesheet type="text/xsl" href="url to XSLT"?> 

When building an XSLT to transform XML to HTML, it is best to break the code into separate templates, just as you would break a set of code into separate functions or modules. The template for the channel node can easily be integrated into the root node, or vice versa. However, doing this limits the extensibility of both nodes. Similarly, separating the processing for the item node provides a local template for manipulating just those nodes.

Converting between XML Syntaxes with XSLT

The second major use for XSLT is to convert between XML formats. The purpose might be to align one format with the one used by a business partner, or because of a version change in your own schema. The technique is similar to creating HTML; however, you create a series of templates based on the source schema and define the result document in those templates.

Figure 8-6 shows what the desired output should look like, starting with the products.xml document used earlier in this chapter. Notice that the product listing is now grouped by the category, and the product name and price are now attributes of the product element.

image from book
Figure 8-6

If you break down the conversion process, you see at least two stages: extracting the category names to ensure they are unique and converting the elements in the product node to attributes. Listing 8-21 shows the XSLT 2.0 stylesheet used to convert the source document. XSLT 2.0 is used to provide access to some of the XPath 2.0 functions, such as replace and lowercase.

Listing 8-21: Conv e rt.xslt

image from book
      <?xml version="1.0" encoding="UTF-8"?>      <xsl:stylesheet version="2.0"        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"        xmlns:xs="http://www.w3.org/2001/XMLSchema"        xmlns:fn="http://www.w3.org/2005/xpath-functions"        xmlns:xdt="http://www.w3.org/2005/xpath-datatypes">        <xsl:import href="formats.xslt"/>        <xsl:output method="xml" version="1.0" encoding="UTF-8"          indent="yes" exclude-result-prefixes="fn xs xdt"/>        <xsl:template match="/">          <products>            <xsl:for-each-group select="catalog/row" group-by="category">              <xsl:sort select="category" data-type="text"/>              <xsl:variable name="cat" select="category"/>              <xsl:variable name="catclean"                select="lower-case(replace(category, '\s+|\\|/', '_'))"/>              <xsl:element name="{$catclean}">                <xsl:apply-templates select="//row[category=$cat]">                </xsl:apply-templates>              </xsl:element>            </xsl:for-each-group>    </products>          </xsl:template>          <xsl:template match="row">          <product>            <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>            <xsl:call-template name="prod"/>          </product>          </xsl:template>          <xsl:template match="product" name="prod">          <xsl:attribute name="name">            <xsl:value-of select="product/name"/>          </xsl:attribute>          <xsl:attribute name="priceUSD">            <xsl:value-of              select="format-number(product/price, '$#.00', 'USD')"/>            </xsl:attribute>          <xsl:attribute name="priceEuro">            <xsl:value-of              select="format-number(product/price, '¤#,00', 'EURO')"/>            </xsl:attribute>          </xsl:template>      </xsl:stylesheet> 
image from book

The first step in this stylesheet is to import the formats.xslt file (see Listing 8-22). This file includes a couple of decimal-format declarations used in the stylesheet. Output is defined as XML, and the xpath-functions, xpath-datatypes, and XML Schema namespaces are excluded from the resulting output. This step is not necessary, but reduces the complexity of the output.

Much of the work in the stylesheet is performed in the root template. It uses the XSLT 2.0 element for-each-group to loop through the categories in the source document. For XSLT 1.0, you can get a similar result using the for-each statement as follows:

      <xsl:for-each select="catalog/row[not (category = preceding::category)]"> 

The two variables cat and catclean are needed because some of the categories include ampersands and slashes. These would interfere with the output document and, therefore, they are replaced with underscores. However, they are needed when applying the child template to select the products.

Listing 8-22: Formats.xslt

image from book
      <?xml version="1.0" encoding="UTF-8"?>      <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">        <xsl:decimal-format name="USD"          decimal-separator="."          grouping-separator=","          NaN="-" />        <xsl:decimal-format name="EURO"          decimal-separator=","          grouping-separator="."          NaN="-" />      </xsl:stylesheet> 
image from book

As currency formats are commonly used as output in XSLT stylesheets, it makes sense to extract them into a common file that can be imported as needed. The formats.xslt file defines two decimal formats using the decimal and grouping separators appropriate for US dollars and Euros.




Professional XML
Professional XML (Programmer to Programmer)
ISBN: 0471777773
EAN: 2147483647
Year: 2004
Pages: 215

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