XML.com: XML From the Inside Out
oreilly.comSafari Bookshelf.Conferences.


Generating XML and HTML using XQuery

December 23, 2002

XQuery is often described as a query language for processing XML databases. But it's also a very nice language for generating XML and HTML, including web pages. In this article we will look at XQuery from this angle.

Tools for Generating Web Pages

There are many tools for generating web pages. Many of these are based on templates. You write an HTML page, but you can embed within it expressions that get calculated by the web server. Here are some popular examples:

  • JSP or JavaServer Pages ( http://java.sun.com/products/jsp/) is a format where Java expressions and commands are embedded in HTML pages. A JSP page is automatically translated into a special kind of Java class, a servlet. A web server can be configured to execute the servlet when receiving web requests. For example,

    <p>3*4 is <%= 3*4%>.</p>

    Evaluating it yields this HTML fragment:

    <p>3*4 is 12.</p>
  • PHP (http://www.php.net/) is a relatively new scripting language that is especially popular for server applications. Simple PHP might look something like this:

    <p>3*4 is <?php echo 3*4 ?>.</p>
  • ASP or Active Server Pages from Microsoft supports embedded interpreted VBScript and JScript code; ASP.NET ( http://www.asp.net) supports other compiled .NET languages. Here is the same example:

    <p>3*4 is <%= 3*4>.</p>
  • Beautiful Report Language( http://brl.sourceforge.net/) (BRL) allows expressions in the Scheme language to be embedded inside templates. BRL is similar to JSP in that it generates Java servlets. Again, the same example:

    <p>3*4 is [(* 3 4)].</p>

You can do the same thing with XQuery:

<p>3*4 is {3*4}.</p>

There is one important difference between XQuery and most template systems. In templates you can nest expressions in some programming language inside HTML. With XQuery you can also nest HTML inside expressions, as in this loop:

for $i in (1 to 10) return
   <p>{$i}*4 is {$i*4}</p>

With XQuery you can also define functions that return HTML fragments, and you can pass those fragments to other functions. With most template systems, you can only create output fragments as strings and pass them around as strings.

A Photo-album Application

In order to demonstrate web page generation with XQuery, I will describe a photo album application. There are lots of such applications around, and while they differ in features, they all have the same basic idea. You throw a bunch of digital images (JPEG files) at the application, and it generates a bunch of web pages. The overview page shows many smaller thumbnail images; if you click on one, you get a bigger version of that image.

There are two basic approaches to building such an application:

  • first, a program that generates all the web pages in advance has advantages: you can use a browser to view the pages on your local disk using a file: URL, even if you aren't running a server. You can even burn the web pages onto a CD-ROM and browse the pages from there. Or you may have an ISP that allows you to put up web pages but charges extra fees to run server scripts.

  • second, a module or script added to a web server that generates the web pages when requested by a browser has different advantages. It saves disk space for the HTML files, though that is trivial compared to the disk space for the JPEG images. More valuable is that the server can present the viewer with multiple styles and preferences. This is most valuable if the server resizes the JPEG images as suitable for the viewer. This approach also makes it easier to upload a collection of new pictures without extra steps.

We will show how you can use XQuery for either approach, starting out with how to generate static web pages in advance. The software, with usage and installation instructions, is available.

For each album we start with an XML file that contains a list of JPEG image files, with some information about each picture. This XML file can be generated using a script that scans the JPEG files in a directory, or it can be created with a text editor.

The following sample index.xml file describes six digital pictures from a car trip to the West Coast of Norway in the summer of 2001. Each photograph is described by a <picture> element. Each picture may be available in three resolutions:

  • The <full-image> element gives the name (and size in pixels) of the original full-size image.

  • The <image> element gives the name and size of the image scaled suitably for viewing in a web page by itself when browsing.

  • The <small-image> element gives the name and size of a thumbnail image.

Listing 1: An index.xml file describing some pictures

<?xml version="1.0"?>
  <title>Trip to Norway</title>
  <text>July 28-30, 2001 Nathan, Per, and John took a quick round trip to the
    Norwegian fjord country.  Here are some highlights.</text>

  <picture id="Lillehammer22">
    <caption>Lillehammer: Ski-jump practice</caption>
    <text>The Lillehammer olympic 90m ski-jumping hill is used for Summer practice.
      You can see a jumper landing.</text>
    <full-image width="1280" height="960">Lillehammer22.jpg</full-image>
    <image width="740" height="555">Lillehammer22p.jpg</image>
    <small-image width="240" height="180">Lillehammer22t.jpg</small-image>

  <!-- more picture elements as desired -->

  <picture id="ViaValdres2">
    <caption>Valdres valley</caption>
    <full-image width="1280" height="960">ViaValdres2.jpg</full-image>
    <image width="740" height="555">ViaValdres2p.jpg</image>
    <small-image width="240" height="180">ViaValdres2t.jpg</small-image>


Generating the Overview Page

Our first task is to generate the overview page. We want at most three thumbnails per line, producing something like Figure 1.

Figure 1

Figure 1: The overview page shows clickable thumbnails of pictures.

This is a nice example that illustrates the kind of non-trivial rearranging that would be difficult to do with a template system or with XSLT and tedious to do with a language like Java.

Here is the main program to generate the overview page:

let $group := document("index.xml")/group

This is simple enough. We call the document function to read the index.xml file. This returns the document root, so we do /group to select the top-level group node, which we pass to the make-group-page function, which does the actual work of creating the web page:

define function make-group-page($group) {
    <style type="text/css">
      a.textual {{ text-decoration: none }}
      table.row {{ padding: 10px }}
      img {{ border: 0 }}
  <body bgcolor="#00AAAA">
{   make-rows(0, $group/picture)}

The value returned by a call to make-group-page is calculated by an element constructor expression, which looks like normal XML data, except you can use curly braces ({...}) to embed XQuery expressions. For example, the <h2> HTML element contains an XQuery expression that selects the <title> child of the $group parameter, and then selects the children (usually a text node) of that <title> child. Note that double curly braces ({{...}}) in the <style> element are used for curly braces that should appear as-is.

Pages: 1, 2, 3, 4, 5, 6

Next Pagearrow