XInclude

XInclude is a very simple “import” facility for XML documents. With the XInclude directive, you can easily include one XML document in another either as XML or as plain (and escaped) text. This means that you can break down your documents into as many files as you see fit and reference the pieces in a simple, standard way. We should note that it is also possible to do this in another way, using XML entity declarations, but they are fraught with problems. XInclude is simpler and does what its name implies, including the specified document at the current location; you just have to declare the proper namespace for the new <include> element. Here is an example:

        <Book xmlns:xi="http://www.w3.org/2001/XInclude">
          <Title>Learning Java</Title>
          <xi:include href="chapter1.xml"/>
          <xi:include href="chapter2.xml"/>
          <xi:include href="chapter3.xml"/>
          ...
        </Book>

We’ve used the namespace identifier xi to qualify the <include> elements that we use to import the chapters of our book. By default, the file is imported as XML content, which means that the parser incorporates the included document as part of our document. The resulting DOM or SAX view will show the merged documents as one. Alternatively, we can use the parse attribute to specify that we want the target included as text only. In this case, the text is automatically escaped for us like a CDATA section. For example, we could use it to include an XML example in our book without danger of it being intepreted as part of our file:

        <Example>
          <Title>The Zoo Inventory Example</Title>
          <xi:include parse="text" href="zooinventory.xml"/>
        </Example>

Here, the entire zooinventory.xml file will be included as nicely escaped text for us (not added to our document as XML).

XInclude also allows for “fallback” content to be specified using a nested fallback element. The fallback element may point to another file or simply hold XML to be used if the included file can’t be found. For example:

<xi:include parse="text " href="zooinventory.xml">
    <xi:fallback href="filenotfound.xml"/>
</xi:include>
 
<xi:include parse="text" href="example.xml">
    <xi:fallback>This example is missing...</xi:fallback>
</xi:include>

In the first case, if zooinventory.xml is not found, the filenotfound.xml file will be included. In the second case, the “missing” text will be included instead of the file. If there is no fallback specified, a parse-time fatal error occurs. An empty fallback element can be used to suppress any error. Fallbacks may also be nested within fallbacks to combine these behaviors.

Getting XInclude to work for us requires simply turning on a couple of flags before we begin parsing our file. First, because the XInclude facility uses namespaces, we have to turn on namespace processing in our parser factory. Second, we have to explicitly tell the parser to interpret the include directives. To modify our PrintDOM example to perform the includes before printing the result, we turn these flags on the factory before creating a DocumentBuilder instance:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
 
// enable XInclude processing
factory.setNamespaceAware( true );
factory.setXIncludeAware( true );
 
DocumentBuilder parser = factory.newDocumentBuilder();
Document document = parser.parse( input );

Both of those options should really be the defaults these days. But they have historically come later to XML and so been treated as special features that have to be enabled. We should also mention before we move on that XInclude can make use of XPath expressions (via an API called XPointer) in order to include just selected parts of an XML document.