Recipe10.6.Creating a Self-Contained HTML Transformation


Recipe 10.6. Creating a Self-Contained HTML Transformation

Problem

You want to package XML data, as well as a stylesheet for converting it to HTML, into a single file.

Solution

This recipe assumes you have a browser that supports client-side XSLT transformations (IE 6.0 or later, also IE 5.x + MSXML 3.0, Netscape Navigator 6.1 or later, Mozilla, Firefox 1.0 or later, Apple Macintosh Safari (Tiger), etc.):

<?xml version="1.0" encoding="UTF-8"?>     <?xml-stylesheet type="application/xml" href="selfcontained.xsl"?>     <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:pf="http://www.ora.com/XSLTCookbook/namespaces/portfolio">     <portfolio xmlns="http://www.ora.com/XSLTCookbook/namespaces/portfolio">   <investment>     <symbol>IBM</symbol>     <current>72.70</current>     <paid>65.00</paid>     <qty>1000</qty>   </investment>   <investment>     <symbol>JMAR</symbol>     <current>1.90</current>     <paid>5.10</paid>     <qty>5000</qty>   </investment>   <investment>     <symbol>DELL</symbol>     <current>24.50</current>     <paid>18.00</paid>     <qty>100000</qty>   </investment>   <investment>     <symbol>P</symbol>     <current>57.33</current>     <paid>63</paid>     <qty>100</qty>   </investment> </portfolio>       <xsl:output method="html" />       <xsl:attribute-set name="gain-loss-font">     <xsl:attribute name="color">       <xsl:choose>         <xsl:when test="(pf:current - pf:paid) * pf:qty >= 0">black</xsl:when>         <xsl:otherwise>red</xsl:otherwise>       </xsl:choose>     </xsl:attribute>   </xsl:attribute-set>           <xsl:template match="xsl:stylesheet">   <xsl:apply-templates select="pf:portfolio"/> </xsl:template>     <xsl:template match="pf:portfolio">     <html>      <head>       <title>My Portfolio</title>      </head>           <body bgcolor="#FFFFFF" text="#000000">       <h1>Portfolio</h1>       <table border="1" cellpadding="2">         <tbody>           <tr>             <th>Symbol</th>             <th>Current</th>             <th>Paid</th>             <th>Qty</th>             <th>Gain/Loss</th>           </tr>           <xsl:apply-templates/>         </tbody>       </table>      </body>     </html> </xsl:template>     <xsl:template match="pf:investment">   <tr>     <td><xsl:value-of select="pf:symbol"/></td>     <td><xsl:value-of select="pf:current"/></td>     <td><xsl:value-of select="pf:paid"/></td>     <td><xsl:value-of select="pf:qty"/></td>     <td><font xsl:use-attribute-sets="gain-loss-font"><xsl:value-of select="format- number((pf:current - pf:paid) * pf:qty, '#,##0.00')"/></font></td>   </tr> </xsl:template>     </xsl:stylesheet>

Two components in this stylesheet make it work.

The first is the xml-stylesheet processing instruction, which tells the browser that the stylesheet associated with the document it loads is the very same document. You can refer to the same document as its stylesheet with HRef="" rather than specifying the name of the file, which is helpful if you ever rename it.

The second is the template that matches the xsl:stylesheet element and redirects stylesheet processing to the embedded XML data. In this case, the elements are in the http://www.ora.com/XSLTCookbook/namespaces/portfolio namespace.

Discussion

This recipe is somewhat of a trick to impress your friends. Intermixing content and styling, in some ways, goes against the spirit of the technology. However, delivering just a single file can be convenient, so you should not feel guilty about using this recipe if it suits your needs.

The official way to achieve these results is to embed the stylesheet in the document rather than vice versa. See http://www.w3.org/TR/xslt#section-Embedding-Stylesheets in the XSLT 1.0 spec or http://www.w3.org/TR/xslt20/#embedded in the XSLT 2.0 spec for more details. However, IE does not yet support embedded stylesheets, so this trick gets around the problem.

You can deliver content in this form without necessarily developing the content directly in this form. The following stylesheet merges a stylesheet and an XML file into the self-contained format. The only two criteria are that the XML must be in a namespace and the stylesheet should not begin processing at the root node (/):

<!-- generate-selfcontained.xslt --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"      xmlns:xso="dummy">     <!-- Reuse the identity transform --> <xsl:import href="../util/copy.xslt"/>     <!-- This stylesheet will be generating stylesheet content       so use xso as alias for xsl --> <xsl:namespace-alias stylesheet-prefix="xso" result-prefix="xsl"/>     <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>     <xsl:strip-space elements="*"/> <!--Not a good idea to strip space from text nodes --> <xsl:preserve-space elements="xsl:text"/>     <!--The name of the file containing xml data --> <xsl:param name="datafile"/> <!-- The name of the resulting output file --> <xsl:param name="outfile"/>     <xsl:template match="/">   <!-- Insert the processing instruction to tell the browser that        $outfile is the stylesheet -->   <xsl:processing-instruction name="xml-stylesheet">    <xsl:text>type="application/xml" href="</xsl:text>    <xsl:value-of select="$outfile"/>"<xsl:text/>     </xsl:processing-instruction>      <xsl:apply-templates/>       </xsl:template>     <xsl:template match="xsl:stylesheet">       <xsl:copy>     <xsl:copy-of select="@*"/>          <xsl:apply-templates/>          <!-- Generate the xslt that tells the       <xso:template match="xsl:stylesheet">       <xso:apply-templates select="{name(document($datafile)/*)}"/>     </xso:template>       <!-- Insert the data -->   <xsl:copy-of select="document($datafile)"/>      </xsl:copy>     </xsl:template>     </xsl:stylesheet>

You can use this stylesheet to transform another stylesheet and its data into a self-contained HTML transformation. The source should be the stylesheet, and the $datafile is provided as a parameter. You need an additional parameter, $outfile, to allow correct generation of the xml-stylesheet processing instruction.

Using Saxon on the command line, the generation might be invoked as:

saxon -o self-contained.xsl pf-portfolio.xslt generate-selfcontained.xslt            datafile="pf-portfolio.xml" outfile="self-contained.xsl"

Where self-contained.xsl is the name of the resulting stylesheet and pf-portfolio.xslt is the stylesheet being merged with pf-portfolio.xml.




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