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, IE 5.x + MSXML 3.0, Netscape Navigator 6.0, 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 elements 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 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 styleshhet 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, 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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.218.127.141