Recipe10.4.Creating Frames


Recipe 10.4. Creating Frames

Problem

You want to generate HTML that organizes content by using HTML frames.

Solution

As in Recipe 10.2, you will use modes to make multiple passes over the XML. First, create the frameset container document. To do so, you use two frames. The smaller left frame holds the names of the salespeople as hyperlinks for activating content in the mainframe. The main frame contains the sales figures for the salesperson selected by the user. This example provides a default main frame that is displayed when the page first comes up:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">     <xsl:output method="html"/>     <xsl:param name="URL"/>     <xsl:template match="/">   <xsl:apply-templates select="*" mode="frameset"/>   <xsl:apply-templates select="*" mode="salespeople_frame"/>   <xsl:apply-templates select="*" mode="sales_frames"/> </xsl:template>     <!-- =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  = --> <!--              Create frameset container (mode ="frameset")      --> <!-- =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  = --> <xsl:template match="salesBySalesperson" mode="frameset">   <!-- Non-standard saxon xsl:document! -->   <xsl:document href="index.html">          <html>      <head>       <title>Salesperson Frameset</title>      </head>      <frameset rows="100%" cols="25%, 75%" border="0">        <frame name="salespeople" src="/books/2/765/1/html/2/salespeople_frame.html" noresize=""/>        <frame name="mainFrame" src="/books/2/765/1/html/2/default_sales.html" noresize=""/>      </frameset>      <body bgcolor="#FFFFFF" text="#000000">      </body>     </html>   </xsl:document> </xsl:template>     <!-- =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  = --> <!-- Create salespeople_frame.html  (mode = "salespeople_frame")    --> <!-- =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  = --> <xsl:template match="salesBySalesperson" mode="salespeople_frame">   <!-- Non-standard xsl: saxon:document! -->   <xsl:document href="salespeople_frame.html">     <html>      <head>        <title>Salespeople</title>      </head>      <body bgcolor="#FFFFFF" text="#000000">        <table>         <tbody>           <xsl:apply-templates mode="index"/>         </tbody>       </table>      </body>     </html>   </xsl:document> </xsl:template>     <xsl:template match="salesperson" mode="index">   <tr>     <td>       <a href="{concat(@name,'.html')}"            target="mainFrame"><xsl:value-of select="@name"/></a>     </td>   </tr> </xsl:template>     <!-- =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  = --> <!--                  Create @name.html  (mode = "content")         --> <!-- =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  = -->     <xsl:template match="salesperson" mode="sales_frames">       <xsl:document href="default_sales.html">     <html>      <head>        <title>Default</title>      </head>           <body bgcolor="#FFFFFF" text="#000000">      <h1><center>Sales By Salesperson</center></h1>       <br/>      Click on a salesperson on the left to load his or her sales figures.      </body>     </html>   </xsl:document>       <xsl:document href="{concat(@name,'.html')}">     <html>      <head>        <title><xsl:value-of select="@name"/></title>      </head>           <body bgcolor="#FFFFFF" text="#000000">      <h1><center>Sales By Salesperson</center></h1>       <h2><xsl:value-of select="@name"/></h2>       <table border="1" cellpadding="3">         <tbody >           <tr>             <th>SKU</th>             <th>Sales (in US $)</th>           </tr>           <xsl:apply-templates mode="content"/>         </tbody>       </table>      </body>     </html>   </xsl:document> </xsl:template>     <xsl:template match="product" mode="content">     <tr>       <td><xsl:value-of select="@sku"/></td>       <td align="right"><xsl:value-of select="@totalSales"/></td>     </tr>      </xsl:template>     </xsl:stylesheet>

Discussion

Frames are useful for splitting a page into logical sections; however, using frames with visible or resizable borders is somewhat passé. Your stylesheet cannot be used for client-side transformation because it outputs many separate HTML filesone for the frameset, one for the left frame that lists salespeople, and a separate page for each salesperson.

The solution demonstrates an example that is dynamic and open-ended in terms of the number of separate pages that might be generated from a single XML file. However, cases in which frames can be used with client-side XSLT processing are more straightforward. Simply create a page containing a frameset where the frames hold separate XML documents, each with their own transformation:

<html>    <head>       <title>Frameset</title>     </head>    <frameset rows="100%" cols="25%, 75%" border="0">       <frame name="leftFrame" src="/books/2/765/1/html/2/left.xml" noresize="">       <frame name="mainFrame" src="/books/2/765/1/html/2/main.xml" noresize="">    </frameset>    <body bgcolor="#FFFFFF" text="#000000"></body> </html>

You must reference different XML documents for each frame because there can be only one xml-stylesheet processing instruction per file. However, you can still keep the content in one stylesheet by using an xinclude link (http://www.w3.org/TR/xinclude/) and an XSLT template to process it.

left.xml looks like this:

<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="application/xml" href="left.xsl"?> <xi:include href="salesBySalesperson.xml"              xmlns:xi="http://www.w3.org/2001/XInclude"/>

main.xml is similar:

<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="application/xml" href="main.xsl"?>  <xi:include href="salesBySalesperson.xml"             xmlns:xi="http://www.w3.org/2001/XInclude"/>

left.xsl and main.xsl contain a template that processes the xinclude element by using the document function:

<!-- left.xsl --> <?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"/>     <xsl:template match="xi:include" xmlns:xi="http://www.w3.org/2001/XInclude">   <xsl:for-each select="document(@href,.)">      <xsl:apply-templates/>   </xsl:for-each> </xsl:template>      <xsl:template match="salesBySalesperson">   <html>    <head>     <title>Salespeople</title>    </head>    <body bgcolor="#FFFFFF" text="#000000">      <table>       <tbody>         <xsl:apply-templates/>       </tbody>     </table>    </body>   </html> </xsl:template>     <xsl:template match="salesperson">   <tr>     <td>       <a href="{concat('main.xml#',@name)}" target="mainFrame">       <xsl:value-of select="@name"/></a>     </td>   </tr> </xsl:template>     </xsl:stylesheet>     <!-- main.xsl --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">   <xsl:output method="html"/>     <xsl:template match="xi:include" xmlns:xi="http://www.w3.org/2001/XInclude">   <xsl:for-each select="document(@href)">      <xsl:apply-templates/>   </xsl:for-each> </xsl:template>      <xsl:template match="salesBySalesperson">     <html>      <head>       <title>Sales By Salesperson</title>      </head>           <body bgcolor="#FFFFFF" text="#000000">      <xsl:apply-templates/>      </body>     </html> </xsl:template>     <xsl:template match="salesperson">      <h1><a name="{@name}"><center>Sales By Salesperson</center></a></h1>       <h2><xsl:value-of select="@name"/></h2>       <table border="1" cellpadding="3">         <tbody >           <tr>             <th>SKU</th>             <th>Sales (in US $)</th>           </tr>           <xsl:apply-templates />         </tbody>       </table>       <div style="padding-top:1000"/> </xsl:template>     <xsl:template match="product">     <tr>       <td><xsl:value-of select="@sku"/></td>       <td align="right"><xsl:value-of select="@totalSales"/></td>     </tr>      </xsl:template>         </xsl:stylesheet>

In the main.xsl stylesheet, you generate named anchors for each salesperson and separate them by a large amount of whitespace by using <div style="padding-top:1000"/>. In left.xsl, you generate links to the anchors. This generation crudely emulates behavior of the multipage example.

See Also

Jeni Tennison's XSLT and XPath on the Edge (M&T, 2001) includes a detailed discussion of client-side XSLT processing with frames that shows how JavaScript can create more sophisticated results.




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