Something I didn’t know about XSLT2′s collection() function. I had previously used it in the form:
<xsl:variable name="files" select="collection(docs.xml)"/>
where docs.xml has a structure of:
<?xml version="1.0"?>
<collection>
<doc href="blort1.xml"/>
<doc href="blort2.xml"/>
</collection>
You can then address, via the variable, the structure of those files blort1 and blort2 and iterate over them etc. e.g. you can do something like:
<xsl:for-each select="$files/tei:TEI/tei:text/tei:div"> <xsl:apply-templates mode="TOC" select="tei:head"/> </xsl:for-each>
Ok… I already knew how to do that and have used it to run XSLT on a whole raft of files. To get the docs.xml file I used to run “xmlstarlet ls” and then I have a dir2collection.xsl that transforms its output to the correct format.
However, what I didn’t know is that I didn’t need to bother creating the collection file at all. Saxon can generate the collection file from a parameter on the URI that you hand collection(). That is you can do something like:
<xsl:variable name="files" select="collection('../foo/?select=blor*.xml')"/>
And $files is then addressable in the same way as if you had made a collection document of all the files matching blor*.xml in the directory ../foo/ (and of course you can just do *.xml)
But wait, that’s not all. You can get a bit more complicated about it, pass the path as a parameter, and supply the collection() function extra parameters. So something like:
<xsl:param name="path2collection">../foo/</xsl:param>
<xsl:variable name="path">
<xsl:value-of
select="concat('../',$path2collection,'?select=*.xml;recurse=yes;on-error=warning')"
/>
</xsl:variable>
<xsl:variable name="docs" select="collection($path)"/>
And thus forth $docs contains a recursive collection of anything in the path2collection parameter you give it.
Isn’t that fun? Ok, maybe only me.