Saturday, 13 January 2007

A few clever tricks with XSLT 2

I've been working, either professionally or personally, with XSLT 2 and Saxon 8 for the best part of the last two years. It is a real step-up from XSLT 1 and I can honestly say I love it even more than XSLT 1. Here are a couple of useful/interesting things I've encountered on the way:

1) Resolving local fragment identifiers within a document. SVG has a mechanism for declaring pieces of reusable mark-up that can be referenced with a <use xlink:href="#someID"/> fragment where #someID is a fragment identifier URL that is resolved within the parent document. When using XSLT 2 to process a document and you wished to resolve that reference you could try the following.

<xsl:sequence select="doc(resolve-uri(@xlink:href, base-uri(root()))"/>

This example treats the fragment identifier as a URI (which it is), it resolves it with respect to the URI of the source document's root and then opens that document and extracts the fragment the identifier points to. Its short and sweet and doesn't require any tedious messing around with substring-after(@xlink:href, '#'). For that matter you could define your own wrapper function called my:resolve-fagment-identifier() that takes a single argument that is the fragment identifier.

2) Now, in saying all that, you could regard the previous reference as something akin to an ID/IDREF. but in examples where you have used the id attribute but don't have a schema or DTD you wont be able to use the XPath id() function.

Or can you?

In a previous post entitled 'Who knows what a node ID is?' I talked about the xml:id attribute. Saxon 8 understands this attribute's intent to uniquely identify its owner element within the scope of the parent document. So put simply, if you don't or wont have a schema/DTD but you do want ID/IDREFs then use xml:id and the id() function.

3) Here's a nice little tip - you have a path expression that must match, for example, one of two attributes.

<xforms:input bind="date" ref="shipping/@date">
....
</xforms:input bind>

In this case the bind attribute has priority over the ref attribute so:

<xsl:value-of select="(@bind, @ref)[1]"/>

The brackets are a sequence constructor and the [1] predicate states that the first item in the sequence will be selected. Where both are present then @bind is selected but in the absence of the bind attribute, @ref will be selected.

Of Schematron, Unit Testing and oXygen...

I've been off the SVG trail for the last three or so months due to a shift in contract work. But, as this blog is not just about SVG, I'd like to pass on my experiences with some truly wonderful things:
  • Schematron - a rules based XML validation language
  • Unit testing - with respect to the above
  • <oxygen/> - an most excellent XML IDE
Schematron, is an example of how you can put existing technologies to very good use. Schematron uses XML and XPath to declaritively express a set of rules that when applied to a source document will test the validity of that source document. But here's the cool part, there is an XSLT implementation of Schematron and what's more - it is, in my opinion, a very good example of what XSLT can do. The XSLT implementation has been written with many hooks to allow overriding of the standard functionality. It is, for example, quite straight forward to customise the report output. I'll say no more than this and advise you to check it out.

Unit Testing, which I'm sure we've all had some involvement with one way or another but for some people its necessary and for others its a necessary evil. Now, considering what I've just been saying about Schematron, a rules based language for validating XML documents, or fragments there of, the light should be coming on about now. Yes, you can use Schematron to validate the results of your XSLT transformations. I could bang on for ages about this but I wont. Have a think and a play.

<oxygen/>, as I've already stated is a most excellent XML IDE, which comes chock full of some wonderful tools including the very good source editor with superb code completion, abbreviations and support for all the main validation languages (including Schematron). It has a sensational debugger that you've got to experience to believe, a profiler that I haven't touched yet but others I know have found it useful and it support XSLT 2 and XQuery via Saxon 8. I'm not kidding when I say - It rocks!!!