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.