Jesper Tverskov, November 12, 2008

Saxon XQuery processor in ASP.NET

There are several XQuery processors for .NET to choose from. In this example I use Saxon having the benefit of also being an XSLT processor. When you have the XQuery part of the processor working or the XSLT 2.0 part, the other one is also ready for use.

1. Saxon’s documentation

Saxon’s .NET API Documentation is not easy reading unless you do .NET programming every day. The About Saxon webpage mentions that saxon-resources9-n.zip (the number will get higher one day) contains additional documentation. The file, the "-n" part of the name is not used any more, can be downloaded from the Saxonica download page, or from http://saxon.sourceforge.net/ ("Documentation and samples"). [1]

Inside saxon-resources9-1-0-1.zip is a "samples/cs" directory and the file examples.cs for both XSLT and XQuery. The best way to open the "cs" file is from inside software knowing what "cs" means like "Visual Studio .Net", "Visual Web Developer 2008 Express Edition", etc.

The proper place to get help for Saxon in ASP.NET is at the Saxon Discussion Forums: Help.

2. What I do in this tutorial

The XQuery examples in saxon-resources9-1-0-1.zip are not easy reading unless you now the ins and outs of .NET programming already. In this tutorial I have simply recreated a very basic example in ASP.NET. When you have my example working, it is much easier to return to the original documentation of Saxon.

All the XQuery examples in "samples/cs" are rather simple, the XQuery being a string of a line or so from inside the Codebehind file. In my example we load both the input document from an XML file and the XQuery from a text file. The XQuery is an ASP.NET version of the XQuery used in my tutorial: Creating XHTML with XQuery, also having a comparison of XQuery and XSLT.

We use XQuery to transform or query "products.xml" into an XHTML table. We do it with a webpage. When a browser requests "products2table.aspx", the XQuery in the Codebehind file transform products.xml to an XHTML webpage server-side and sends it to the browser.

3. How make ASP.NET find Saxon

Here is the easy way. Let us use the free edition, Saxon-B. Download and unzip "saxonb9-1-0-3n.zip" (the number will get higher one day). It contains a "bin" directory. Simply copy the files in the "bin" directory to a "bin" directory at the root of your ASP.NET website.

At the top of the CodeFile, you can now insert:

using Saxon.Api;

That's it!

4. Input XML file

products.xml

<?xml version="1.0"?>
<products>
  <product id="p1">
    <name>Delta</name>
    <price>800</price>
    <stock>4</stock>
    <country>Denmark</country>
  </product>
  <product id="p2">
    <name>Golf</name>
    <price>1000</price>
    <stock>5</stock>
    <country>Germany</country>
  </product>
  <product id="p3">
    <name>Alfa</name>
    <price>1200</price>
    <stock>19</stock>
    <country>Germany</country>
  </product>
  <product id="p4">
    <name>Foxtrot</name>
    <price>1500</price>
    <stock>5</stock>
    <country>Australia</country>
  </product>
  <product id="p5">
    <name>Tango</name>
    <price>1225</price>
    <stock>3</stock>
    <country>Japan</country>
  </product>
</products>

5. XQuery file

The XQuery below is the same as the XQuery discussed in more detail in my tutorial, Creating XHTML with XQuery. Only the prolog with serialization parameters have been removed and inserted in the aspx.cs CodeFile instead.

products2table.xquery

<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <style type="text/css">
      body{{font-family: Verdana, Arial, Helvetica, sans-serif}}
      table, th, td{{border: 1px solid gray; border-collapse:collapse}}
      .alt1{{background-color:mistyrose}}
      .alt2{{background-color:azure}}
      .th{{background-color:silver}}
    </style>
    <title>Using XQuery</title>
  </head>
  <body>
    <h1>Using XQuery</h1>
    <table cellspacing="0" cellpadding="5">
      <tr class="th">
        <th>no</th>
        <th>id</th>
        <th>name</th>
        <th>price</th>
        <th>stock</th>
        <th>country</th>
      </tr>
      {for $a at $b in *:products/*:product return
      <tr class="{if ($b mod 2 = 0) then "alt1" else "alt2"}">
        <td>{$b}</td>
        <td> {$a/@id/data(.)}</td>
        <td>{$a/*:name/data(.)}</td>
        <td>{$a/*:price/data(.)}</td>
        <td>{$a/*:stock/data(.)}</td>
        <td>{$a/*:country/data(.)}</td>
      </tr>}
    </table>
  </body>
</html>

Please note that the XQuery above uses wildcards for namespaces to make it ease to create XHTML when input XML is in no namespace. This method is considered "quick and dirty" and should only be used for tests. My tutorial, Creating XHTML with XQuery, shows some better but more cumbersome methods.

6. aspx webpage

products2table.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="products2table.aspx.cs" Inherits="_products2table" %>

7. aspx.cs (codefile)

products2table.aspx.cs

using System;
using System.IO;
using Saxon.Api;

public partial class _products2table : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {
    Processor processor = new Processor();
    //Input loaded from xml file
    XdmNode indoc = processor.NewDocumentBuilder().Build(new Uri(Server.MapPath("products.xml")));
    
    //XQuery loaded from text file
    StreamReader query = new StreamReader(File.Open(Server.MapPath("products2table.xquery"), FileMode.Open));
    XQueryCompiler compiler = processor.NewXQueryCompiler();
    XQueryExecutable exp = compiler.Compile(query.ReadToEnd());
    XQueryEvaluator eval = exp.Load();
    eval.ContextItem = indoc;

    Serializer qout = new Serializer();
    qout.SetOutputProperty(Serializer.METHOD, "xml");
    qout.SetOutputProperty(Serializer.DOCTYPE_PUBLIC, "-//W3C//DTD XHTML 1.0 Strict//EN");
    qout.SetOutputProperty(Serializer.DOCTYPE_SYSTEM, "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd");
    qout.SetOutputProperty(Serializer.INDENT, "yes");
    qout.SetOutputProperty(Serializer.OMIT_XML_DECLARATION, "no");

    qout.SetOutputWriter(Response.Output);
    eval.Run(qout);
  }
}

For a discussion of serializing to "xml" and to "xhtml", see my tutorial, Creating XHTML with XQuery.

8. Output XHTML

The browser requests products2table.aspx. Using the XQuery, the codebehind file transforms products.xml to XHTML and sends it to the browser.

Footnotes

[1]

This tutorial is a remake of my tutorial XSLT 2.0 Saxon in ASP.NET using XQuery instead and focusing on a concrete example, "products2table".

Updated 2009-11-13