The first advantage of XTP is that it separates the JSP code from the
page. The page design can just use a standard HTML/XML editor. More
importantly, since it's easy to create tags, you can create tags
meaningful for your specific application.
The XTP templates example is an expansion of the JSP "model 2" example. You may want to
refer to Resin's
support of XSLT and JSP .
The guest book uses three application-specific tags
Tag | Meaning
|
ct:guest-book | iterates over the guest book entries.
|
ct:guest-name | writes the guest's name.
|
ct:guest-comment | writes the guest's comment.
|
Compare the login.xtp page with the
login.jsp in the JSP
templates example.
login.xtp
<?xml-stylesheet href='guestbook.xsl'?>
<title>Hogwarts Comments</title>
<table width='100%'>
<tr>
<td width='25%'><em>Name</em></td>
<td width='75%'><em>Comment</em></td>
</tr>
<ct:guest-book>
<tr>
<td><ct:guest-name/>
<td><ct:guest-comment/>
</ct:guest-book>
</table>
|
HTML tags should be copied to the generated output. So we just
create a default rule to copy the input to the output. XSLT is a
pattern based language. 'node()' matches any node and '@*' matches any
attribute. So any tag that doesn't match any other rules will be
copied.
It's important to notice that XSLT works with XML trees, not text
streams like JSP. The xsl:copy of an attribute adds and attribute
to the containing element.
defaultcopy.xsl: strict XSLT
<xsl:template match='node()|@*'>
<xsl:copy>
<xsl:apply-templates select='node()|@*'/>
</xsl:copy>
</xsl:template>
|
Strict XSLT follows the XML syntax. There are several advantages of
using XML but readability is not one of them. To make stylesheets
more readable we've added some simple syntactic sugar to XSLT,
called XSLT-lite. XML purists can stick to the standard XML syntax:
Resin supports both. You can look at our XSLT and
XSLT-lite
references and also some
XSLT-lite examples.
XSLT-lite makes scanning templates easier because the template
pattern is clear, on its own line. The following is exactly
equivalent to the defaultcopy.xsl above.
defaultcopy.xsl: XSLT-lite
node()|@*
<<
<xsl:copy>
<xsl:apply-templates select='node()|@*'/>
</xsl:copy>
>>
|
guestbook.xsl contains the custom tags for the guestbook example.
When Resin looks at a node, it will select the best matching pattern
and execute it. The element <ct:guest-book> will generate a loop,
while <form action='GuestXtp'> will copy the form to the output.
guestbook.xsl
<!-- Use language=javascript for the XSLT -->
<xtp:directive.page language=javascript/>
<xsl:import href='defaultcopy.xsl'/>
<!-- Generated JSP uses language=javascript -->
/
<<
<jsp:directive.page language='javascript'/>
<xsl:apply-templates/>
>>
ct:guest-book
<<
<% for (var _ct_guest in application.attribute.guest_book) { %>
<xsl:apply-templates/>
<% } %>
>>
ct:guest-name
<<
<%= _ct_guest.name %>
>>
ct:guest-comment
<<
<%= _ct_guest.comment %>
>>
|
So now we've created some tags for a custom application. That's
nice and it shows how XSLT can clean JSP pages. The guest book JSP
was fairly simple so the added complexity of creating stylesheets
doesn't really show how powerful the XTP concept is. For a taste of
real power, we'll create a simple form library.
Adding addition functionality to forms makes HTML and JSP complex.
GuestXtp just adds simple filling in of default values. The GuestXtp
servlet calls request.setAttribute to set default values for
form element. For example, once a user has added a comment, she can
edit the comment. The default value is the old comment.
In fact, the w3c now has a new requirements document for the next
generation of intelligent forms. That doesn't really help web
designers because web sites still need to support old browsers. XTP
gives web sites the more powerful functionality now.
There are a few other common form extensions:
- Server defaults
- Server validation
- Client validation
- Client actions
The XTP file itself is simple. It just looks like any HTML page,
except form values are called ct:*.
login.xtp
<form action='GuestXtp' method='post'>
<ct:hidden name='action' value='login'/>
<table>
<tr><td>Name<td><ct:input name='Name'/>
<tr><td>Password<td><ct:password name='Password'/>
<tr><td colspan=2>Hint: the password is quidditch
<tr><td/><td><ct:submit value='Login'/>
</form>
|
The transformation is relatively simple. Copy all properties to
the output and add a value attribute if the servlet supplied a default value.
<ct:input size=40 name='Name'/> |
<input name=Name size=40 value='Harry Potter'> |
|
XSLT lets stylesheets pull common formatting code into functions
using the named template mechanism. The template functions are called
with xsl:call-template. xsl:call-template works like
xsl:apply-templates, but it passes the current node, not the children
nodes.
Because the generated JSP will add an attribute at run time, the
form.xsl treats its output as unparsed content. Unknown elements,
like <form> or <input> are printed as text. Unparsed content
works just like JSP.
fun:copy-attrs is a simple XSLT function which copies the
attributes from the XTP element to the output. In the ct:input example above,
it will copy name=Name and size=40.
xtp:cache tells Resin that the XSLT results are cacheable. Once
it's generated the JSP, it doesn't need to run the XSLT engine again.
This greatly improves the performance.
form.xsl
<xsl:stylesheet parsed-content='false'>
<xtp:cache/>
<xsl:template name='fun:copy-attrs'>
<xsl:for-each select='@*'>
<xsl:text> </xsl:text><{name(.)}>="<{.}>"<xsl:text/>
</xsl:for-each>
</xsl:template>
|
fun:input-attrs is the core of the form processing. It calls
fun:copy-attrs to copy the user's attributes. Then it generates the
JSP to add a value attribute if it's available.
<xsl:template name='fun:input-attrs'>
<xsl:call-template name='fun:copy-attrs'/>
<xsl:if test='@value'>
value="<{@value}>"
</xsl:if>
<xsl:if test='not(@value)'>
<% {
var _ct_v = request.attribute["<{@name}>"];
if (_ct_v == null)
_ct_v = "";
out.write(' value="', _ct_v.replace('"', """), '"');
}
%>
</xsl:if>
</xsl:template>
|
Now that the functions have been defined, creating the individual
tags is simple.
ct:input
<<
<input <xsl:call-template name='fun:input-attrs'/>>
>>
ct:password
<<
<input type='password' <xsl:call-template name='fun:input-attrs'/>>
>>
ct:submit
<<
<input type=submit <xsl:call-template name='fun:input-attrs'/>>
>>
|
XTP is a tradeoff. It takes more work to design custom tags than to
write standard inline JSP. However, once you've written the tags,
using them is a breeze. In the next few months, we'll start building
useful libraries of tags similar to Perl's CGI.pl.
An important value of XTP is that it lets web pages use the latest
W3C specifications without waiting for all the browsers to support
it. For example, the W3C has proposed requirements for intelligent
forms. A properly designed form.xsl can implement intelligent forms
on the server and support all browsers, not just the browsers
supporting the spec.
Copyright © 1998-2005 Caucho Technology, Inc. All rights reserved.
Resin® is a registered trademark,
and HardCoretm and Quercustm are trademarks of Caucho Technology, Inc. | |
|