XSLT: Multiple XML Inputs

How to create one result document from more sources? It's easy with XSLT!


Let's imagine, that we have two (or more) XML documents as the data sources. In our example we will use a list of products as the first document and a list of attributes (colors, in this case) as the second document. Each product as a ID of a color as its attribute, the name of the color is in the list of colors. We would like to show all the products with their color names in a nice HTML table.

Data sources

products.xml

<?xml version="1.0" encoding="UTF-8"?>
<products>
  <product id="1001" color="A1">
    <name>Strawberry</name>
  </product>
  <product id="1002" color="A2">
    <name>Blueberry</name>
  </product>
  <product id="1003" color="A2">
    <name>Plum</name>
  </product>
  <product id="1004" color="A3">
    <name>Green Apple</name>
  </product>
</products>

colors.xml

<?xml version="1.0" encoding="UTF-8"?>
<colors>
  <color id="A1">
    <name>Red</name>
  </color>
  <color id="A2">
    <name>Blue</name>
  </color>
  <color id="A3">
    <name>Green</name>
  </color>
</colors>

XSLT Transformation

transformation.xsl

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

  <xsl:param name="colorsFile"/>
  <xsl:variable name="colorsDoc" select="document($colorsFile)"/>

  <xsl:template match="/">
    <html>
    <body>
    <table border="1" cellpadding="10">
      <tr bgcolor="#accfff">
        <th>Name</th>
        <th>Color</th>
      </tr>
      <xsl:for-each select="products">
        <xsl:apply-templates select="product"/>
      </xsl:for-each>     
    </table>
    </body>
    </html>
  </xsl:template>

  <xsl:template match="product">
    <tr>
      <td><xsl:value-of select="name"/></td>
      <td>
         <xsl:variable name="colorId" select="@color"/>
          <xsl:value-of select="$colorsDoc/colors/color[@id=$colorId]/name"/>
      </td>
    </tr>
  </xsl:template>

</xsl:stylesheet>

The parameter colorsFile takes its value from the processor (below), could be set to a file path like:

<xsl:param name="colorsFile" select="'../input/colors.xml'" />

Java processor

In this article we're using a Java processor, the solution can be but very easily converted to the pure XSLT solution and another processor (for instance an internet browser) can be used.

All the classes are from the sub-packages of the package javax.xml.

final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

final DocumentBuilder builder = factory.newDocumentBuilder();
final Document document = builder.parse("products.xml");

final TransformerFactory tFactory = TransformerFactory.newInstance();
final Transformer transformer = tFactory.newTransformer(new StreamSource("transformation.xsl"));

transformer.setParameter("colorsFile", "colors.xml");

transformer.transform(new DOMSource(document), new StreamResult("output.html"));

And that's exactly what we wanted!

output.html

Name Color
Strawberry Red
Blueberry Blue
Plum Blue
Green Apple Green