AxKit.org [logo curtesy of http://xml.com]
--sep--
Start Navigation
About AxKit
Index
xml.apache.org
Features
Live Sites
Installation
Documentation
Daily Churn
Getting AxKit
License
Download
Mailing List
Contribute
CVS
Support
Bugs
End Navigation
Prev Top Next

Dynamic Content

AxKit has a flexible tool for creating XML from various data sources such as relational databases, cookies, and form parameters, called eXtensible Server Pages, or XSP. This technology was originally invented by they Apache Cocoon team, and we share their syntax [F]3[/F]. This allows easier migration of projects to and from Cocoon.

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 like AxKit.

The XSP framework allows you to add in extra tags into your XML to provide custom functionality. These extra tags are called taglibs. By using taglibs, rather than embedding Perl code in your XSP page, you can further build on AxKit's separation of content from presentation, by separating out logic too. There are several taglibs that are available for AxKit's XSP engine already on CPAN.

Handling Form Parameters

The AxKit::XSP::Param taglib allows you to easily read form and querystring parameters within an XSP page. The following example shows how a page can submit back to itself. To allow this to work, the following needs to be added to your httpd.conf:

AxAddXSPTaglib AxKit::XSP::Param

Then the XSP page is:

<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 factor about the above is how we freely mix XML tags with our Perl code, and the XSP processor figures out the right thing to do depending on context. There is a consequence of this, in that the XSP page itself must be valid XML, so 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>

In order to get around this restriction, there are a number of ways we can code this in XML. 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 &lt;, 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. It is also worth noting 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. Two examples would be:

<xsp:logic>
if (<param:name/>) {
  # xsp:content needed
  <xsp:content>
  Your name is: <param:name/>
  </xsp:content>
}
</xsp:logic>

versus the case when there is a 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 only by 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 processed with XSLT or XPathScript to be reasonably viewable in a browser, however the point is that you can re-use the above page as either HTML or WML just by applying different stylesheets.

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:

AxAddXSPTaglib AxKit::XSP::Cookie

And the XSP page is:

<xsp:page
 xmlns:xsp="http://apache.org/xsp/core/v1"
 xmlns:cookie="http://axkit.org/NS/xsp/cookie/v1"
 language="Perl"
>
<page>
  <xsp:logic>
  my $value;
  if ($value = <cookie:fetch name="count"/>) {
    $value++;
  }
  else {
    $value = 1;
  }
  </xsp:logic>
  <cookie:create name="count">
    <cookie:value><xsp:expr>$value</xsp:expr></cookie:value>
  </cookie:create>
  <p>Cookie value: <xsp:expr>$value</xsp:expr></p>
</page>
</xsp:page>

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 both of the above examples we have used a taglib tag within a Perl if() statement. These tags have both been expressions, even though they don't use the <xsp:expr> syntax. In XSP, everything understands its context, and tries to do the right thing. This way, the following three examples would work as expected:

<cookie:value>3</cookie:value>

<cookie:value><xsp:expr>2 + 1</xsp:expr></cookie:value>

<cookie:value><param:cookie_value/></cookie:value>

We see this as an extension of how Perl works - the idea of "Do What I Mean", or DWIM.

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, along with email sending using the Mail::Sendmail module (which will interface either to an SMTP server, or direct to the sendmail executable). 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:

<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.

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 we can implement form validation using exceptions:

<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 (see below).

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, and so a "<" character would be encoded as "&lt;"). The AxKit Util taglib is a direct copy of the Cocoon Util taglib, and as such uses the same namespace as the Cocoon Util taglib: http://apache.org/xsp/util/v1.

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 (the latter uses the Util taglib, which must be installed in order to be able to use the ESQL 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 [F]4[/F], again helping 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:

AxAddXSPTaglib AxKit::XSP::ESQL

An example ESQL usage which reads data from an address book table is below. This page demonstrates how it is possible to re-use the same code for both our list of addresses, and viewing a single address in detail.

<xsp:page
 language="Perl"
 xmlns:xsp="http://apache.org/xsp/core/v1"
 xmlns:esql="http://apache.org/xsp/SQL/v2"
 xmlns:except="http://axkit.org/NS/xsp/exception/v1"
 xmlns:param="http://axkit.org/NS/xsp/param/v1"
 indent-result="no"
>
<addresses>
 <esql:connection>
  <esql:driver>Pg</esql:driver>
  <esql:dburl>dbname=phonebook</esql:dburl>
  <esql:username>postgres</esql:username>
  <esql:password></esql:password>
  <except:try>
  <esql:execute-query>
   <xsp:logic>
   if (<param:address_id/>) {
    <esql:query>
     SELECT * FROM address WHERE id =
     <esql:parameter><param:address_id/></esql:parameter>
    </esql:query>
   }
   else {
    <esql:query>
     SELECT * FROM address
    </esql:query>
   }
   </xsp:logic>
   <esql:results>
    <esql:row-results>
     <address>
      <esql:get-columns/>
     </address>
    </esql:row-results>
   </esql:results>
  </esql:execute-query>

<except:catch>
 Error Occured: <except:message/>
</except:catch>
</except:try>
     </esql:connection>
    </addresses>
    </xsp:page>

The result of running the above through the XSP processor is:

<addresses>
 <address>
  <id>2</id>
  <last_name>Sergeant</last_name>
  <first_name>Matt</first_name>
  <title>Mr</title>
  <company>AxKit.com Ltd</company>
  <email>matt@axkit.com</email>
  <classification_id>1</classification_id>
 </address>
</addresses>

Prev Top Next

Printer Friendly
Raw XML