Sarissa to the Rescue

Client-side XML processing. Today's browsers do cover the
basics and some of them go even further, offering support for
XHTML, SVG, XSLT, XPath , XLink, validation using W3C XML Schema,
and more. This article will introduce you to basic cross-browser
XML development with the aid of Sarissa, an ECMAScript library
designed to stop those nasty incompatibilities before they get too
close.

Getting Started

Using XML on the client enables you to do things you've never
done before, especially when it comes to control of structured
information and delivering an enhanced user experience. Let's
go over some typical examples.

Your favorite designer could very well be hiding this from
you: it is possible to update only parts of a web page
with data coming from a request to your server without
refreshing the page and without scripting between those
troublesome iframe elements. The request can
be the result of user interaction handled by your
script. Using the
XMLHttpRequest object, you can perform
requests over HTTP and obtain the XML response as a
DOM-compatible object. You can then process that object
further, if you want, before finally injecting it into the
document using plain DOM methods, adding to your usability
and saving bandwidth.

Use of XML on the client side is often driven by server-side
requirements. For example, a high number of concurrent requests
involving XSLT-based transformations sounds like trouble for any
server. A transformation requires three tree structures in memory,
one for each of the source, transform, and result documents.
Outsourcing the transformation process to capable clients is a
little like outsourcing the process of furniture assembly to the
clients themselves. They get what they want more quickly and pay
less while you save resources without losing the sale. After the
assembly, clients keep the screwdriver for future use much the same
way a browser will cache your XSLT document.

Another use case may involve sending structured
information to the server application. To perform this,
you can create a DOM document programmatically (even by
parsing an XML string), perhaps processing it further, and
finally submit it to the server.

You get the idea. This can go on to complex applications with rich
UIs, for example a web-based XML editor based on XSLT, DOM, and CSS.

But let's go over the basics first.

Basic Training

The real issue in client-side XML development is browser
incompatibility around implementations and extensions of
the W3C DOM. The Sarissa library hides these
incompatibilities for you, also adding some useful
utilities into the mix.

A typical script block dealing with XML starts with instantiating a
DOM document. With Sarissa, getting a new XMLDocument
object is done by calling a 'static' method:

In standards-based browsers, this block is equal to
document.implementation.createDocument. In IE, Sarissa
just uses the most recent MSXML ProgId to construct an
ActiveX-based object as appropriate. Additionally, you can
pass two string parameters to that factory method, which correspond
to a namespace URI and a local name respectively. Those are used by
Sarissa to create a root element and add it to the newly
constructed XMLDocument:

We first load the remote file using the load
method of a XMLDocument using synchronous
loading, meaning that the if branch will only
be executed after the load method returns.
Then we check for a parsing error. If an error exists, the
user sees the result of a call to
Sarissa.getParseErrorText, which provides a string
with a human-readable description of the error. If there is no
error, the user sees the XML string serialization of the document
returned from Sarissa.serialize. This is like IE's
xml property of DOM Nodes, with the difference being that it
works for everyone.

More Tricks

The XMLHttpRequest object, available by one name or another in every major browser by now, is used
when you simply need more control over the request to the
remote server, like specifying the HTTP method and
headers. You can use it to load the same XML file as above
like:

What we've done here is create a new
XMLHttpRequest object and configure it to
request the specified URL using HTTP GET
asynchronously. We then perform the actual request and
when that returns, we serialize the response XML which is
available via the responseXML property.

To perform XSLT transformations, two
XMLDocument objects are needed,
one for the XSLT transform and one for the source
document. Supposing we have obtained those
as xslDoc and
xmlDoc respectively, we can perform the
transformation using an XSLTProcessor:

// create an instance of XSLTProcessor
var processor = new XSLTProcessor();
// configure the processor to use our stylesheet
processor.importStylesheet(xslDoc);
// transform and store the result as a new doc
var resultDocument =
processor.transformToDocument(xmlDoc);
// show transformation results
alert(Sarissa.serialize(resultDocument));

Here we create a new processor and load our stylesheet to
it using the importStylesheet method. It is worth noting
that a single configured instance
of XSLTProcessor can be re-used to transform
more than one source document. We don't have to load
the stylesheet each time. Then we store the transformation
result into a new XMLDocument object and
display its serialization to the user.

You may be aware that IE has added the transformNode and
transformNodeToObject methods in its
implementation of the XMLDocument
object. Sarissa does implement those methods for Mozilla
but they are deprecated. The use of
the XSLTProcessor is recommended as it
provides a more efficient way to transform multiple
documents and set XSLT parameters. A last word on XSLT --
Right now XSLT and XPath stuff are not supported for
Konqueror and Safari, although this is expected to change.

Injections

Playing with XML programmatically is cool, but we usually want to
modify our page using the resulting markup. Suppose we want
to inject an XML node bound as fooNode in our document
as a child of an element with an id value of
'targetNode':

It is possible to get into trouble with this code. Although it's the most efficient way to append the node in the
document, it could result to an error if, for example, the
node you are trying to append is a document
node. Serializing with
Sarissa.serialize and setting the
innerHTML of the target element is always an option,
but I would suggest doing it properly using DOM instead.

The Final Touch

So all of this is great but it's still too much code
to write, and probably too error-prone, especially if you
are a code completion wimp like me. Moreover, the case
becomes worse if you want to use XSLT on the client where
applicable. To do that, you need to work on both end
points:

your server must be able to transform the XML
before sending it, or leave the transformation to
the client. This can be dependent on the URL
requested or an HTTP parameter.

The client must know if it is able to perform the
transformation and ask the XML as appropriate.
IS_ENABLED_XSLTPROC is a Boolean constant you
can check in your logic to figure out what to do.

With these two issues addressed, you could result in something like

// set an HTTP parameter depending on whether you want
// the transformation on the server or not
var clientTransform = Sarissa.IS_ENABLED_XSLTPROC;
// now construct the URL as appropriate
var url = 'path/to/file?sent-as-is=' + clientTransforml;

So we have constructed the URL we want thanks to a Sarissa constant
that tells us whether our client is able to use a transformer. Now,
supposing we still want to append the result
targetElement as with our previous example
and with an instance of XSLTProcessor at hand
(which may be null), we perform this with just one line:

Sarissa.updateContentFromURI(url, targetElement, processor);

This will work if the URL does point to an HTTP server. If
you cannot have access to one, just use your filesystem
instead; you will need to load or build the source
document manually and call
Sarissa.updateContentFromNode with it.

Client-side XML can open new doors for your
applications. Using Sarissa, it can be easy as
well. Sarissa includes a lot more and the code can even
guide you in writing your own reusable components. Give it
a try and let me know what you are up to. Maybe next time
I'll show you how to build a browser-based XML editor.