Generating XML and HTML using XQuery
by Per Bothner
|
Pages: 1, 2, 3, 4, 5, 6
Running XQuery programs from CGI scripts
CGI scripts are programs or scripts that are executed by a web server in response to a request. The request parameters are passed to the script as environment variable. The script writes the result parameters followed by the data (usually an HTML page) to standard output; the server takes that output and sends it back as an HTTP response.
You can have a CGI script call an XQuery processor to generate the result. Using CGI scripts will not give you high performance, especially if you have to start up an XQuery processor on each request. However, CGI doesn't require any server modification or configuration, and it may be fast enough for some applications. It may be most useful for testing simple XQuery applications.
Another problem running XQuery from CGI scripts is that there is no standard for accessing request parameters from XQuery. The Qexo implementation provides a set of functions that is a subset of the servlet functionality. Qexo provides a wrapper script that runs a servlet and uses the CGI environment variable to provide a subset of the servlet functionality. For example, you can write a little XQuery program like this:
response-content-type("text/html"),
<html>
<p>The request URL was: request-url()</p>
<p>{let $query := request-query-string() return
if ($query)
then ("The query string was: ",$query)
else "There was no query string."}</p>
</html>
If this is in the file hello.xql, you compile it to a
servlet thus:
kawa --servlet --xquery -C hello.xql
Copy the resulting .class file(s) to your web server's CGI
directory. On Red Hat GNU/Linux using the Apache server, you can do the
following (as root):
cp hello*.class /var/www/cgi-bin/
Next find the cgi-servlet program that Kawa builds and
installs. If you installed Kawa in the default place, it will be in
/usr/local/bin/cgi-servlet. (You'll have this if you
installed Kawa from source, but not if you're just using the Kawa
.jar file.) Copy this program into the same CGI
directory:
cp /usr/local/bin/cgi-servlet /var/www/cgi-bin/
Make sure the files have the correct permissions:
chmod a+r /var/www/cgi-bin/hello*.class /var/www/cgi-bin/hello chmod a+x /var/www/cgi-bin/hello
Now you should be able to run the Kawa program, using the URL http://localhost/cgi-bin/hello. It may take a few seconds to get the reply, mainly because of the start-up time of the Java VM, which is why servlets are preferable. The CGI interface can still be useful for testing or if you can't run servlets.
Comparing XSLT and XQuery
XSLT is a popular and powerful language for transforming an input XML document into an output document. The latter can be XML, HTML, or plain text. XSLT became a W3C recommendation (standard) in 1999; it's being revised in conjunction with the XQuery standardization process because XSLT uses XPath for expressions and patterns and XPath is also a subset of XQuery.
The most visible difference between XSLT and XQuery is that an XSLT program (a stylesheet) is actually an XML document. This can sometimes be useful, but it has the big disadvantage that XSLT stylesheets, in spite of their simplicity, can be both verbose and hard to read.
The more significant difference between XSLT and XQuery is the
execution model, specifically the flow of control. Except for XQuery's
unusual data types, it is otherwise a relatively normal programming
language, with explicit control flow. (Strictly speaking XQuery does not
have a defined control flow, as an implementation is free to evaluate
expressions in whatever order is consistent with the standard. Still, you
can understand an XQuery program in terms of a conventional
execution model.) In contrast, executing an XSLT stylesheet is controlled
by a template processor, which matches a node against a set of
templates, selects the template whose pattern that most closely matches
the input node, and then executes that template. This process may then be
repeated by the <xsl:apply-templates> instruction,
which recursively calls the template processor on the child nodes of the
current node.
Using pattern matching to drive the execution in this way is very powerful and usually convenient. It works best when doing relatively simple conversions that can be expressed using patterns. You can do more complex programming using XSLT, but it can quickly become very awkward and verbose.
Transforming DocBook to HTML using XSLT
As an example application, consider converting DocBook to HTML, using both XSLT and XQuery. DocBook is a popular SGML/XML format for writing technical documentation. It's used for manuals and help files by, among many others, the Linux Documentation Project and the Gnome project.
Listing 3 is a simple (and incomplete) XSLT stylesheet for translating DocBook to HTML.
Listing 3: An XSLT stylesheet for transforming DocBook to HTML
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="sect1/title">
<h2 class="title"><xsl:apply-templates/></h2>
</xsl:template>
<xsl:template match="sect2/title">
<h3 class="title"><xsl:apply-templates/></h3>
</xsl:template>
<xsl:template match="artheader/title">
<h1><xsl:apply-templates/></h1>
</xsl:template>
<xsl:template match="artheader/subtitle">
<h2><xsl:apply-templates/></h2>
</xsl:template>
<xsl:template match="artheader/authorgroup">
<h3><i><xsl:apply-templates/></i></h3>
</xsl:template>
<xsl:template match="biblioentry/abbrev">[<xsl:apply-templates/>]</xsl:template>
<xsl:template match="biblioentry/title"><cite><xsl:apply-templates/></cite></xsl:template>
<xsl:template match="biblioentry/authorgroup"><xsl:apply-templates/>.</xsl:template>
<xsl:template match="article">
<html>
<head>
<xsl:if test="artheader/title">
<title><xsl:value-of select="artheader/title"/></title>
</xsl:if>
</head>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="title">
<title><xsl:apply-templates/></title>
</xsl:template>
<xsl:template match="abstract">
<div type='abstract'><h3>Abstract</h3><xsl:apply-templates/></div>
</xsl:template>
<xsl:template match="element">
<p><xsl:apply-templates/></p>
</xsl:template>
<xsl:template match="para">
<p><xsl:apply-templates/></p>
</xsl:template>
<xsl:template match="screenshot">
<img src='{mediaobject/imageobject/imagedata[@format="PNG"]/@fileref}' />
</xsl:template>
<xsl:template match="caption">
<p><b><xsl:apply-templates/></b></p>
</xsl:template>
<xsl:template match="emphasis"><em><xsl:apply-templates/></em></xsl:template>
<xsl:template match="citation">[<xsl:apply-templates/>]</xsl:template>
<xsl:template match="quote">"<xsl:apply-templates/>"</xsl:template>
<xsl:template match="classname"><code><xsl:apply-templates/></code></xsl:template>
<xsl:template match="function"><code><xsl:apply-templates/></code></xsl:template>
<xsl:template match="itemizedlist">
<ul><xsl:apply-templates/></ul>
</xsl:template>
<xsl:template match="listitem">
<li><xsl:apply-templates/></li>
</xsl:template>
<xsl:template match="sect1">
<div class="sect1">
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="sect2">
<div class="sect2">
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="programlisting">
<pre><xsl:apply-templates/></pre>
</xsl:template>
<xsl:template match="bibliography">
<div class="bibliography"><h2>Bibliography</h2><xsl:apply-templates/></div>
</xsl:template>
<xsl:template match="biblioentry">
<p><xsl:apply-templates/></p>
</xsl:template>
</xsl:stylesheet>