Active Template Pages
ATP (Active Template Pages) is based on XSL stylesheets. The documentation for the specific tags is in the XSL stylesheet section. This section describes how ATP works. ATP lets web designers create active pages without changing the original text. It uses a separate XSL stylesheet to transform the original document into a fancy formatted document. Because the active stylesheet is separate from the passive content, ATP gives designers a tighter focus. When worrying about style, designers can concentrate on the stylesheet. When concentrating on content, designers can focus on the text. ATP makes the input file simpler: it can be plain old HTML. It separates the content (*.atp) from the style (*.xsl). The tradeoff is that XSL stylesheets are slightly more complicated than JSP active pages. For JSP, scripts execute exactly where they're placed. ATP has to match HTML to script fragments using patterns. ATP works by matching stylesheet patterns to the input HTML, creating the result HTML following the pattern actions. ATP analyzing the input HTML into a structured HTML tree using the XML document object model. For each node, it finds the best pattern in the XSL and applies the action. The action prints to the output HTML.
Blank Stylesheet Example
In this example, we're using a blank stylesheet. Even with a blank stylesheet, Resin does something useful: it prints out all text, removing the tags.
hello.atp
<TITLE>Hello, world</TITLE> <H1>Hi, World!</H1> <P>The hello, world example is simple.
Resin first reads in the ATP file, parsing it like an HTML file. It adds optional tags, like <html> and </p> and forces all HTML tags to be lower case.
hello$9342.dom
<html> <head> <title>Hello, world</title> </head> <body> <h1>Hi, World!</h1> <p>The hello, world example is simple.</p> </body> </html>
Next, Resin starts its matching process at the top. Since the stylesheet is empty, it uses the default rules. The default rules say: process an element's children and print a text node's data.
#document, process children <html>, process children <head>, process children <title>, process children "Hello, world", print to output <body>, process children <h1>, process children "Hi, World!", print to output <p>, process children "The hello, ...", print to output
hello$9342.html
Hello, world Hi, World! The hello, world example is simple.
Simple Page Template
Resin's ATP can create standard page layout: common backgrounds, navigation, headers and footers. This is a common use for any of the active content creation tools. This example adds two things to the default stylesheet. All elements are copied instead of ignored, and the body of the HTML gets a background and a margin. Copying elements is easy. The copy template matches all elements `match='*'`. When Resin processes a node whose pattern matches nothing else, it will execute the copy action. The action copies the element (`xsl:copy-element`) and processes the children (`xsl:apply-templates`).
<xsl:template match='*'> <xsl:copy-element> <xsl:apply-templates/> </xsl:copy-element> </xsl:template>
For the page template pattern, we use `match='/html/body'`. Resin will execute the template in place of the body. We could have used `match='body'` and for most ATP pages that would work fine. But if someone created an internal <body> tag, say in the middle of a table, that body tag would get the top level decoration. Probably not what was intended.
<xsl:template match='/html/body'> <!-- cyan background --> <body bgcolor='cyan'> <table width='100%'> <!-- left margin --> <tr><td width='240'></td> <!-- center column --> <td width='80%'> <!-- insert body contents --> <xsl:apply-templates/> <!-- copyright footer --> <hr> Copyright &copy; 1999 Caucho Technology </td></tr> </table> </body> </xsl:template>
The translation follows the same order as in the blank stylesheet example. The body rule is used for the body and the copy-element rule is used for every other tag.
<TITLE>Hello, world</TITLE> <H1>Hi, World!</H1> <P>The hello, world example is simple.
<html> <head> <title>Hello, world</title> </head> <body bgcolor='cyan'> <table width='100%'> <tr><td width='240'></td> <td width='80%'> <h1>Hi, World!</h1> <p>The hello, world example is simple. </p> <hr> Copyright &copy; 1999 Caucho Technology </td></tr> </table> </body> </html>
Creating a Custom Tag
All by itself, the template example is cool. But here's something more interesting, creating a custom tag. In this case, we'll just create a simple counter. To use the counter tag, just add it to the ATP file.
counter.atp
A counter example:<counter/>
A counter example: 2
Here's the addition to the stylesheet file.
default.xsl
<xsl:template match='counter'> <#= application.attribute.counter++ #> </xsl:template>
The `xsl:template` tag says we're defining a new tag. The `match='counter'` tells Resin to apply the counter tag whenever it sees `<counter/>`. JavaScript code is between the special expression tags '<#=' and '#>'. Resin will insert the value of the expression into the generated text. The application object is the same as for JSP. In fact, stylesheets can use any of the JSP implicit variables.
Mixing ATP and JSP
Resin actually creates a JSP file after processing a ATP file. It then evaluates the JSP file to create the output HTML. So the actual processing order is: Parse ATP file as HTML Find and parse XSL stylesheet Applying the stylesheet to the ATP, creating a JSP file Execute the JSP file Here's we're going to take advantage of this by creating a named counter. If the counter has an 'id' attribute, we'll use it at the value of the application variable. Scripts use the counter the same as before:
counter.atp
A counter example: <counter id='test'/>
Here's the patterns to do it. The `xsl-cache` directive tells Resin that it can cache the generated JSP file. Resin can cache the file because it only depends on the ATP file, not on the request or on a random number.
default.xsl
<?xsl-cache?> <xsl:template match='counter'> <# var id = elt.attribute.id if (id) { #> <%= application.attribute["<#= id #>"] %> <# } else { #> <%= application.attribute.counter++ %> <# } #> </xsl:template>
The following JSP file is the result. Resin will execute the generated JSP file to produce the result. Because default.xsl was marked as cached, on following requests Resin will merely reexecute 'gen438.jsp'.
gen438.jsp
A counter example: <%= application.attribute["test"]++ %>
Using Clever Patterns
The previous example can be rewritten by using more clever XQL patterns. One pattern matches counters with id attributes. Another matches other counters. So the following stylesheet does the same thing as the previous one.
<?xsl-cache?> <xsl:template match='counter'> <%= application.attribute.counter++ %> </xsl:template> <xsl:template match='counter[@id]'> <%= application.attribute["<#= elt.attribute.id #>"] %> </xsl:template>
Copyright © 1998-2000 Caucho Technology. All rights reserved. Last modified: Thu, 16 Sep 1999 14:56:48 -0700 (PDT)