Recipe10.2.Creating Hyperlinked Documents


Recipe 10.2. Creating Hyperlinked Documents

Problem

You want to convert XML into hyperlinked HTML content.

Solution

A typical course of action when converting XML into HTML is to make two or more passes over the XML to create menu or index pages and content pages. The menu pages contain links to the content pages. (Only an XSLT 1.0 solution is needed here.) The following solution generates an index and summary pages for SalesBySalesPerson.xml (see Chapter 2):

<xsl:stylesheet version="1.0"     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:saxon="http://icl.com/saxon"   extension-element-prefixes="saxon">     <xsl:output method="html"/>     <xsl:template match="/">   <xsl:apply-templates select="*" mode="index"/>   <xsl:apply-templates select="*" mode="content"/> </xsl:template>     <!-- =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  = --> <!--                Create index.html  (mode = "index")                        --> <!-- =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  = --> <xsl:template match="salesBySalesperson" mode="index">   <saxon:output href="index.html">          <html>      <head>        <title>Sales By Salesperson Index</title>      </head>           <body bgcolor="#FFFFFF" text="#000000">       <h1>Sales By Salesperson</h1>       <xsl:apply-templates mode="index"/>      </body>     </html>   </saxon:output> </xsl:template>     <xsl:template match="salesperson" mode="index">   <h2>     <a href="{concat(@name,'.html')}">       <xsl:value-of select="@name"/>     </a>   </h2> </xsl:template>     <!-- =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  = --> <!--               Create @name.html  (mode = "content")                       --> <!-- =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  = -->     <xsl:template match="salesperson" mode="content">   <saxon:output href="{@name}.html">          <html>      <head>         <title><xsl:value-of select="@name"/> Sales</title>      </head>           <body bgcolor="#FFFFFF" text="#000000">       <h1><xsl:value-of select="@name"/> Sales</h1>       <ol>           <xsl:apply-templates mode="content"/>       </ol>      </body>     </html>   </saxon:output> </xsl:template>     <xsl:template match="product" mode="content">     <li><xsl:value-of select="@sku"/>&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;$<xsl:value- of select="@totalSales"/></li> </xsl:template>     </xsl:stylesheet>

Notice how the modes separate the transformation of XML elements into index content versus the information content of each salesperson's HTML page. Modes are used commonly in HTML transformations because they allow data to be mapped onto presentation in multiple ways within a single stylesheet.

As designed, this stylesheet is limited to batch processing. You can parameterize it to control which document gets created. This parameter also removes the need for the nonstandard saxon:output extension (which is also unnecessary if you use XSLT 2.0):

<xsl:stylesheet version="1.0"   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">     <xsl:output method="html"/> <!--Used to specify which document to output--> <!--INDEX : creates the index document --> <!--Sales Person's name : creates the page for that salesperson -->  <xsl:param name="which" select="'INDEX'"/>     <xsl:template match="/">   <xsl:choose>     <xsl:when test="$which='INDEX'">       <xsl:apply-templates select="*" mode="index"/>     </xsl:when>     <xsl:otherwise>       <xsl:apply-templates select="*/salesperson[@name = $which]"                             mode="content"/>     </xsl:otherwise>   </xsl:choose> </xsl:template>     <!-- =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  = --> <!--            Create index.html  (mode = "index")                 --> <!-- =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  = --> <xsl:template match="salesBySalesperson" mode="index">   <!-- Removed saxon:output. The rest is the same. --> </xsl:template>     <!-- ... -->     <xsl:template match="salesperson" mode="content">   <!-- Removed saxon:output. The rest is the same. --> </xsl:template>     <!-- ... -->     </xsl:stylesheet>

This technique would be slightly more robust if each salesperson used an ID rather than her name as the parameter.

Discussion

The solution does not create fancy content, but it does illustrate the basic mechanics of producing linked HTML content. To produce all web pages with a single stylesheet, you were forced to use a nonstandard XSLT 1.0 element (saxon:output). Similar extensions are available in most processors, and XSLT 2.0 has XSL:result-document.

The stylesheet produces relative links, which is what you want most of the time. However, when you need absolute links, rather than hardcoding a URL, you might consider incorporating a top-level parameter that can be set to the URL:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">     <xsl:output method="html"/>     <xsl:param name="URL" select="http://www.mycompany.com/"/>     <!-- elided ... -->     <xsl:template match="salesperson" mode="index">   <h2>     <a href="{$URL}{@name}.html'">       <xsl:value-of select="@name"/>     </a>   </h2> </xsl:template>

See Also

See Recipe 6.6 for more information on producing multiple output documents.

The content produced by these transformations is not very user friendly. Recipe 10.3 and Recipe 10.4 show how to improve the result's aesthetics.




XSLT Cookbook
XSLT Cookbook: Solutions and Examples for XML and XSLT Developers, 2nd Edition
ISBN: 0596009747
EAN: 2147483647
Year: 2003
Pages: 208
Authors: Sal Mangano

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