24 September 2012

Using multiple input documents for XSLT transformation

I believe I'm not alone when I need to use couple of input documents for a XSLT transformation. It's rather common case to have input data from multiple sources, to process it and to return a single result. Should XSLT be an exception? Not this time.
If we look at data type mapping it obvious that we could accept and return Nodes, NodeLists, etc. We could do the same with transformer parameters as well. Here is an example:

Document doc = ...; // direct input for transformer
Document anotherDoc = ...; // second document to be passed as parameter

TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(xsl);
transformer.setParameter("anotherDoc", anotherDoc);
transformer.transform(new DOMSource(doc), new StreamResult(System.out));

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    exclude-result-prefixes="xsl">

  <xsl:param name="anotherDoc" />

  <xsl:variable name="inputDoc" select="/" />

  <xsl:template match="/">
    <xsl:apply-templates select="$anotherDoc/anotherRoot" />
  </xsl:template>


  <xsl:template match="nodeOfAnotherDoc">
    <xsl:value-of select="text()" />
    <xsl:value-of select="$inputDoc/root/@attr" />
  </xsl:template>

</xsl:stylesheet>

That's all the trick, we could operate of another document just on regular xsl:variable containing a node-set.
Just one hint: it may be useful to have a variable referencing input document root (inputDoc in example), because inside context of xsl:template that matched anotherDoc you may have trouble accessing nodes of input document.