Here’s another one of those really obscure things that will probably not be important to anyone at all, ever. Anyway, it took me a while to work it out so I’m going to record it here for future reference.
The problem: using XSLT, I wanted to pass a node-tree as a parameter to a template and then loop over it using xsl:for-each. Now I can already sense XSLT purists’ hackles rising: yes I should probably have tried harder to come up with some way of achieving the same thing using template matching. But please take pity on my poor brain! It really hasn’t managed to absorb all the subtleties of XSLT yet (even after two years battling with it) and as hard as I tried, I just couldn’t achieve what I needed to in a pure functional way. I know, I know: I’m going to hell.
Anyway, first off I worked out that to pass a node-tree as a parameter you have to use xsl:copy-of rather than xsl:value-of (which just flattens the node-tree into a string). But then, just as I was celebrating getting over that particular hurdle, I found that trying to use a variable in a for-each statement like this (simplified for readability):
<xsl:template> <xsl:with-param name="data"/> <xsl:for-each select="$data/*"> </xsl:for-each> </xsl:template>
…gave an ‘Invalid Type’ error.
The key (at least as far as libxslt, the XSLT parser library used by PHP5, is concerned), is something called EXSLT. As the acronym suggests, EXSLT provides extensions to XSLT. One of these is a function called node-set(), which “returns a node-set from a result tree fragment”. Bingo!
To get EXSLT to work, first you need to add it to your stylesheet declaration:
Then just call the function (remembering to include the exslt: namespace):
<xsl:template> <xsl:with-param name="data"/> <xsl:for-each select="exslt:node-set($data)/*"> </xsl:for-each> </xsl:template>
NB: if you’re using PHP5, you’ll need to ensure that EXSLT is enabled on your PHP installation. To do this, you can check the result of the XSLTProcessor->hasExsltSupport() method.