XSLT 2.0 in production

Volume 8, Issue 168; 31 Dec 2005; last modified 08 Oct 2010

Or, “what I did on my winter vacation.”

Sun is closed in the last week of December and one of my goals for this vacation was converting all the stylesheets that generate content for this site to XSLT 2.0. (I had a bunch of other goals too: switching my laptop to Solaris, getting some new DocBook releases out, upgrading the server in the closet to Ubuntu, etc., but this one I actually achieved.)

Anticlimactically, if I was successful, you can't tell. It took me a few days, mostly because in any code-review you find cruft you can remove or functions that you can improve. Every experience that I have with XSLT 2.0 increases my enthusiasm for it. So many things are made so much easier by the introduction of sequences, user-defined functions, and direct access to result trees.

The most tentative decision I made was to abandon RDF Twig and return to processing RDF/XML directly with XSLT. I'm relying on the output of cwm to produce a single XML document containing all my RDF encoded very regularly. Then with a couple of keys and a variable binding to hold the RDF, this function makes access to parts of the graph straightforward:

<xsl:function name="f:get-rdf" as="element()?">
  <xsl:param name="about"/>

  <xsl:choose>
    <xsl:when test="empty($about)">
      <xsl:sequence select="$about"/>
    </xsl:when>
    <xsl:when test="$about instance of element()">
      <xsl:choose>
        <xsl:when test="$about/@rdf:nodeID">
          <xsl:variable name="node"
                        select="key('nodeID', $about/@rdf:nodeID, $allrdf)"/>
          <xsl:choose>
            <xsl:when test="$node">
              <xsl:sequence select="$node"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:sequence select="$about"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:when>
        <xsl:when test="$about/@rdf:resource">
          <xsl:variable name="node"
                        select="key('about', $about/@rdf:resource, $allrdf)"/>
          <xsl:choose>
            <xsl:when test="$node">
              <xsl:sequence select="$node"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:sequence select="$about"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:when>
        <xsl:otherwise>
          <xsl:sequence select="$about"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="key('about',string($about), $allrdf)"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

The way it works is that if you pass it an element with an rdf:nodeID or rdf:resource attribute, it returns the node in the graph with that identifier. If you pass it a string, URI, attribute, or something else, it treats it like a URI and finds the node in the graph identified by that URI. What that means in practice is that if you've got a property or value in your hand, you can pass it to f:get-rdf and you'll get back the rdf:Description element in the graph for the right node. Handy.

I've still got a little bit of tidying to do around the edges, most especially in the area of trip itineraries which aren't handling the fact that my RDF PIM stores all the times in UTC very well. Oh, and all the XSL FO used for PDF output is still generated with XSLT 1.0.

If you notice anything wrong, it's probably a bug, so please let me know.

And Happy New Year!

Comments

Bruce pointed out that I had broken comments. Have I fixed them? I think so. (But I just noticed that the previous/next links are broken; something to fix tomorrow.)

—Posted by Norman Walsh on 01 Jan 2006 @ 10:15 UTC #

Yup, it works again now. My question was:

Have you considered just using SPARQL and piping the returned XML results to the XSLT processor from there?

I need to figure out how to adapt citeproc to RDF, and was thinking about doing something like this.

Also, I take it you use a key to index all the rdf:Description nodes?

—Posted by Bruce D'Arcus on 02 Jan 2006 @ 04:24 UTC #

Bruce, I have a couple of keys for the rdf:Description elements. With respect to SPARQL, there isn't really any single query that would give me the information I want. If I reimplemented rdftwig, I'd probably provide a mechanism to submit SPARQL queries to it, though.

—Posted by Norman Walsh on 10 Jan 2006 @ 04:01 UTC #