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.

No comments:

Post a Comment