XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition (733 page)

BOOK: XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition
3.86Mb size Format: txt, pdf, ePub

http://localhost:8080/servlets/servlet/GedServlet?tree=kennedy6&id=I1

If things fail (and they probably will—servlets can be delicate animals), then you will probably see a summary message on the browser window, but the detailed diagnostics will be on the Tomcat console, or in its log files. Good luck!

Generating HTML Using ASP.NET Pages

If you work in a Microsoft environment, an alternative to writing Java servlets to perform server-side transformation is to control the process using an ASP.NET program. In this case you have a choice: you can use Microsoft's XSLT 1.0 processor, referred to by its assembly name
System.Xml.Xsl
, or you can use the Saxon processor in its .NET version. Microsoft have let it be known that they have an XSLT 2.0 processor under development, but it will be a while before it becomes publicly available.

When you can get by with XSLT 1.0, ASP.NET offers a handy

control that you can use to invoke a transformation. You can simply write a page (say
transmog.aspx
) that looks something like this:

<%@ Page Language=“C#” %>


   

      Transmogrification

   

   

     

              DocumentSource=“content.xml”

              TransformSource=“stylesheet.xsl”/>

   


There's a lot more to the

control than this, of course, but because it doesn't let you use XSLT 2.0, it's out of scope for this book.

If you choose the Saxon route, you will have to write a little bit more code. The stylesheet is exactly the same as on the Java platform: the only thing that's different is the controlling application. Saxon on the .NET platform has its own API, which was designed from first principles, taking some good ideas from both the Java and .NET worlds, but not copying either. The API is documented at
http://www.saxonica.com/documentation/dotnetdoc/
. The key steps are:

1.
Create a Saxon
Processor
.

Processor processor = new Processor;

2.
Create an XSLT Compiler.

XsltCompiler compiler = processor.NewXsltCompiler();

3.
Compile the stylesheet; the result is an
XsltExecutable
object. Keep this in an application-level cache:

XsltExecutable executable = compiler.Compile();

4.
Build the source document:

DocumentBuilder builder = processor.NewDocumentBuilder();

XdmDocument document =  builder.Build(inputStream);

5.
Create a serializer for the result of the transformation, connecting this to the response object that represents the HTTP response:

Serializer serializer = new Serializer();

serializer.SetOutputWriter(Response.Output);

6.
Run the transformation. Call the
Load()
method on the
XsltExecutable
to create an
XsltTransformer
. Supply any parameters using the
SetParameter()
method on the
XsltTransformer
, then run the transformation using its
Run()
method.

XsltTransformer transformer = executable.Load();

transformer.SetParameter(….);

transformer.Run(serializer);

Here's a complete example (
ged.aspx
). I've added some basic diagnostics, because until everything is configured correctly, it can be very hard to see what's going on. The
true
parameter to the
Processor()
call indicates that a schema-aware Saxon processor is required, and the code then checks for the failure that occurs when Saxon can't find the license file (don't do this in production, it's not very security-conscious!). I've also included code to display any XSLT compilation errors on the browser screen, because this is much more convenient than having them lost in a log file somewhere.

<%@ Page Debug=“true” Language=“C#” %>

<%@ Import Namespace=“System” %>

<%@ Import Namespace=“System.IO” %>

<%@ Import Namespace=“Saxon.Api” %>


void Page_Load(Object sender, EventArgs e) {

    Uri sourceUri = new Uri(Server.MapPath(Request.QueryString[“tree”] + “.xml”));

    Uri xsltUri = new Uri(Server.MapPath(“ged-aspx.xsl”));

    Processor processor = new Processor(true);

    if (!processor.IsSchemaAware) {

        Response.Output.WriteLine(“

Failed to load Saxon-SA (SAXON_HOME = ” +

                   Environment.GetEnvironmentVariable(“SAXON_HOME”) + “)

”);

    }

    DocumentBuilder builder = processor.NewDocumentBuilder();

    builder.SchemaValidationMode = SchemaValidationMode.Strict;

    XdmNode input = builder.Build(sourceUri);

    XsltCompiler compiler = processor.NewXsltCompiler();

    compiler.ErrorList = new ArrayList();

    XsltExecutable executable;

    try {

        executable = compiler.Compile(xsltUri);

    } catch (Exception err) {

        Response.Output.WriteLine(“

Failed to compile stylesheet

”);

        foreach (StaticError error in compiler.ErrorList) {

            Response.Output.WriteLine(“

At line ” + error.LineNumber + “: ”

                                       + error.Message + “

”);

        }

        return;  

    }

    XsltTransformer transformer = executable.Load();

    transformer.InitialContextNode = input;

    transformer.SetParameter(new QName(“”, “id”),

                             new XdmAtomicValue(Request.QueryString[“id”]));

    transformer.SetParameter(new QName(“”, “tree”),

                             new XdmAtomicValue(Request.QueryString[“tree”]));

    Serializer serializer = new Serializer();

    serializer.SetOutputWriter(Response.Output);

    transformer.Run(serializer);

}


This example makes no attempt to cache either the compiled stylesheet or the source document, which you would typically do by storing the
input
and/or
executable
objects in Application State.

The stylesheet that this uses,
ged-aspx.xsl
, is yet another overlay on the basic
person.xsl
code. This time it creates the hyperlinks like this:


  

                separator=“”/>


There's no space here for a detailed tutorial on ASP.NET. However, it may be worth listing briefly the steps I took to get this working, starting from scratch on a machine running Vista:

1.
Activate IIS (Internet Information Server)—the software is already present on the machine, but it needs to be activated, which you can do via Control Panel ⇒ Programs ⇒ Turn Windows Features On and Off.

2.
Create a simple static Web site (a single
index.html
page will do) to make sure IIS is working. (Start IIS manager, find the default Web site, and use Basic Settings to set the physical path to the directory holding the HTML files (say
d:/wwwroot
). Then enter
http://localhost/
in the browser.)

3.
Download and install Microsoft .NET framework version 1.1.

4.
Download and install Saxon-SA (version 9.0.0.2 or later), and obtain a free evaluation license from
http://www.saxonica.com/
. Install the Saxon DLL files in the Global Assembly Cache using the .NET framework administration tool in the Control Panel, and also copy them to (in our example) a directory
d:/wwwroot/bin/)
. Place the
saxon-license.xml
file in the same
/bin
directory, and set the environment variable SAXON_HOME to
“d:/wwwroot”
.

5.
Copy the files
kennedy6.xml
,
gedSchema.xsd
,
person.xsl
,
ged-aspx.xsl
,
xhtml1-transitional.xsd
, and
ged.aspx
to
d:/wwwroot
. All these files are in the download archive for this chapter.

6.
Enter
http://localhost/ged.aspx?tree=kennedy6&id=I1
in the URL field of your browser.

Needless to say, there are quite a few things that can go wrong along the way, but these are popular technologies so there are some good tutorials available.

Generating HTML in the Browser

Finally, let's look at another way to display the family tree: namely, to download the whole XML file to the browser as a single chunk and then use client-side scripts to invoke stylesheet processing whenever the user clicks on a hyperlink.

The problem with this approach is that at the time of writing, there is no XSLT 2.0 processor available in either Internet Explorer or Firefox; both support XSLT 1.0 client-side transformation, but not yet 2.0. Hopefully, this situation will change in time, though there is always a drawback in running client-side applications because not all your users will be using the latest browser versions.

However, this book would not be complete if it didn't show you how to run transformations client-side, and for that purpose I have written an XSLT 1.0 version of the stylesheet.

My first attempt to do this was to produce the 1.0 version of the stylesheet as an overlay on the 2.0 version: that is, I wrote an XSLT 1.0 module in which every top-level declaration in the 2.0 stylesheet that contained constructs that would only run under XSLT 2.0 was replaced by a functionally equivalent 1.0 construct. My thinking was that the forward-compatibility rules in XSLT 1.0 would ensure that no errors were raised because of constructs in the unused part of the stylesheet. Unfortunately, it didn't prove possible to do this. To see why, look at the rule:


  


This uses XSLT 2.0 constructs (the
data()
function and the
“instance
of”
operator) within the match pattern, and there is no way of overriding this with an XSLT 1.0 template rule in a way that an XSLT 1.0 processor will understand. Even the
use-when
attribute doesn't help, because an XSLT 1.0 processor won't understand it. So I simply copied the common code into the 1.0 module by cut-and-paste to create a freestanding XSLT 1.0 stylesheet, which is named
person10.xsl
. This stylesheet simply leaves out many of the more interesting aspects of the 2.0 version; for example, dates are output as they appear in the GEDCOM data, and no attempt is made to sort children or spouses in chronological order.

Other books

Candyfloss by Nick Sharratt
A Truck Full of Money by Tracy Kidder
Shifters' Storm by Vonna Harper
The Dark Trilogy by Patrick D'Orazio
Full Measures by Rebecca Yarros
Njal's Saga by Anonymous
The Orion Assignment by Camacho, Austin S.
Miracle at the Plate by Matt Christopher