AxKit has a flexible tool called eXtensible
Server Pages (XSP) for creating XML from various data sources
such as relational databases, cookies, and form parameters. This
technology was originally invented by the Apache Cocoon team, and
AxKit shares their syntax. This allows easier migration of projects
to and from Cocoon. (Cocoon allows you to embed Java code in your
XSP, similar to how AxKit allows you to embed Perl code.)
XSP is an XML-based syntax that uses namespaces to provide
extensibility. In many ways, this is like the Cold Fusion model of
using tags to provide dynamic functionality. One of the advantages of
using XSP is that it is impossible to generate invalid XML, which
makes it ideal for use in an XML framework such as AxKit. Another is
that the tags can hide complex functionality, allowing the XSP tags
to be added by designers and freeing programmers to perform more
complex and more cost-effective tasks.
The XSP framework allows you to design new tags, or use ones provided
already by others on CPAN. These extra tags
are called taglibs.
By using taglibs instead of embedding Perl code in your XSP page, you
can further build on AxKit's separation of content
from presentation by separating out logic too. And creating new
taglibs is almost trivial using AxKit's
TagLibHelper module, which hides all the details
for you.
In the examples below, we are going to show some code that embeds
Perl code in the XSP pages. This is not a recommended practice, due
to the ease with which you can extract functionality into tag
libraries. However, it is more obvious to Perl programmers what is
going on this way and provides a good introduction to the technology.
E.3.1. Handling Form Parameters
The AxKit::XSP::Param taglib
allows you to easily read form and query string
parameters within an XSP page. The following example shows how a page
can submit back to itself. To allow this to work, add the following
to your httpd.conf file:
<xsp:page
xmlns:xsp="http://apache.org/xsp/core/v1"
xmlns:param="http://axkit.org/NS/xsp/param/v1"
language="Perl"
>
<page>
<xsp:logic>
if (<param:name/>) {
<xsp:content>
Your name is: <param:name/>
</xsp:content>
}
else {
<xsp:content>
<form>
Enter your name: <input type="text" name="name" />
<input type="submit"/>
</form>
</xsp:content>
}
</xsp:logic>
</page>
</xsp:page>
The most significant thing about this example is how we freely mix
XML tags with our Perl code, and the XSP processor figures out the
right thing to do depending on the context. The only requirement is
that the XSP page itself must be valid XML. That is, the following
would generate an error:
<xsp:logic>
my $page = <param:page/>;
if ($page < 3) { # ERROR: less-than is a reserved character in XML
...
}
</xsp:logic>
We need to convert this to valid XML before XSP can handle it. There
are a number of ways to do so. The simplest is just to reverse the
expression to if (3 > $page), because the
greater-than sign is valid within an XML text section. Another way is
to encode the less-than sign as <, which
will be familiar to HTML authors.
The other thing to notice is the <xsp:logic>
and <xsp:content> tags. The former defines a
section of Perl code, while the latter allows you to go back to
processing the contents as XML output. Also note that the
<xsp:content> tag is not always needed.
Because the XSP engine inherently understands XML, you can omit the
<xsp:content> tag when the immediate child
would be an element, rather than text. For example, the following
example requires the <xsp:content> tag:
<xsp:logic>
if (<param:name/>) {
# xsp:content needed
<xsp:content>
Your name is: <param:name/>
</xsp:content>
}
</xsp:logic>
But if you rewrote it like this, it wouldn't,
because of the surrounding non-XSP tag:
<xsp:logic>
if (<param:name/>) {
# no xsp:content tag needed
<p>Your name is: <param:name/></p>
}
</xsp:logic>
Note that the initial example, when processed by only the XSP engine,
will output the following XML:
<page>
<form>
Enter your name: <input type="text" name="name" />
<input type="submit"/>
</form>
</page>
This needs to be processed with XSLT or XPathScript to be reasonably
viewable in a browser. However, the point is that you can reuse the
above page as either HTML or WML just by applying different
stylesheets.
E.3.2. Handling Cookies
AxKit::XSP::Cookie is a taglib
interface
to Apache::Cookie (part of the
libapreq package). The following example
demonstrates both retrieving and setting a cookie from within XSP. In
order for this to run, the following option needs to be added to your
httpd.conf file:
This page introduces the
concept
of XSP expressions, using
the
<xsp:expr> tag. In XSP, everything that
returns a value is an expression of some sort. In the last two
examples, we have used a taglib tag within a Perl if(
)statement. These tags are both expressions, even though
they don't use the
<xsp:expr>syntax. In XSP, everything
understands its context and tries to do the right thing. The
following three examples will all work as expected:
We see this as an extension of how Perl works—the idea of
"Do What I Mean," or DWIM.
E.3.3. Sending Email
With the AxKit::XSP::Sendmail taglib, it
is
very simple to send email from an XSP page. This taglib combines
email-address verification, using the Email::Valid
module, with email sending, using the
Mail::Sendmailmodule
(which will either interface to an SMTP server or use the
sendmail executable directly). Again, to allow
usage of this taglib, the following line must be added to
httpd.conf:
AxAddXSPTaglib AxKit::XSP::Sendmail
Then sending email from XSP is as simple as what's
shown in Example E-5.
Example E-5. sendmailtaglib.xsp
<xsp:page
xmlns:xsp="http://apache.org/xsp/core/v1"
xmlns:param="http://axkit.org/NS/xsp/param/v1"
xmlns:mail="http://axkit.org/NS/xsp/sendmail/v1"
language="Perl"
>
<page>
<xsp:logic>
if (!<param:email/>) {
<p>You forgot to supply an email address!</p>
}
else {
my $to;
if (<param:subopt/> eq "sub") {
$to = "axkit-users-subscribe@axkit.org";
}
elsif (<param:subopt/> eq "unsub") {
$to = "axkit-users-unsubscribe@axkit.org";
}
<mail:send-mail>
<mail:from><param:user_email/></mail:from>
<mail:to><xsp:expr>$to</xsp:expr></mail:to>
<mail:body>
Subscribe or Unsubscribe <param:user_email/>
</mail:body>
</mail:send-mail>
<p>(un)subscription request sent</p>
}
</xsp:logic>
</page>
</xsp:page>
The only thing missing here is some sort of error handling. When the
sendmail taglib detects an error (either in an
email address or in sending the email), it throws an exception.
E.3.4. Handling Exceptions
The exception taglib, AxKit::XSP::Exception,
is used to catch exceptions. The
syntax is very simple: rather than allowing different types of
exceptions, it is currently a very simple
try/catch block. To use the
exceptions taglib, the following has to be added to
httpd.conf:
AxAddXSPTaglib AxKit::XSP::Exception
Then you can implement form validation using exceptions, as Example E-6 demonstrates.
Example E-6. exceptiontaglib.xsp
<xsp:page
xmlns:xsp="http://apache.org/xsp/core/v1"
xmlns:param="http://axkit.org/NS/xsp/param/v1"
xmlns:except="http://axkit.org/NS/xsp/exception/v1"
language="Perl"
>
<page>
# form validation:
<except:try>
<xsp:logic>
if ((<param:number/> > 10) || (0 > <param:number/>)) {
die "Number must be between 0 and 10";
}
if (!<param:name/>) {
die "You must supply a name";
}
# Now do something with the params
</xsp:logic>
<p>Values saved successfully!</p>
<except:catch>
<p>Sorry, the values you entered were
incorrect: <except:message/></p>
</except:catch>
</except:try>
</page>
The exact same try/catch (and
message) tags can be used for sendmail and for
ESQL (discussed in a moment).
E.3.5. Utilities Taglib
The AxKit::XSP::Util taglib includes
some
utility methods for including XML from the filesystem, from a URI, or
as the return value from an expression. (Normally an expression would
be rendered as plain text, so a
"<" character
would be encoded as
"<"). The
AxKit utilities taglib is a direct copy of the Cocoon utilities
taglib, and as such uses the same namespace as the Cocoon Util
taglib, http://apache.org/xsp/util/v1.
E.3.6. Executing SQL
Perhaps the most interesting taglib of all is the ESQL taglib, which allows
you to execute SQL queries against a DBI-compatible database and
provides access to the column return values as strings, scalars,
numbers, dates, or even as XML. (Returning XML requires the utilities
taglib.) Like the sendmail taglib, the ESQL
taglib throws exceptions when an error occurs.
One point of interest about the ESQL taglib is that it is a direct
copy of the Cocoon ESQL taglib. There are only a few minor
differences between the two, such as how columns of different types
are returned and how errors are trapped.[65] Having nearly identical taglibs helps
you to port projects to or from Cocoon. As with all the other
taglibs, ESQL requires the addition of the following to your
httpd.conf file:
[65]In Cocoon
there are ESQL tags for trapping errors, whereas AxKit uses
exceptions.
AxAddXSPTaglib AxKit::XSP::ESQL
Example E-7 uses ESQL to read data from an
address-book table. This page demonstrates that it is possible to
reuse the same code for both our list of addresses and viewing a
single address in detail.