XInclude Examples

Beginning with version 0.9, eXist comes with partial support for the XInclude standard. If configured (as is the default), eXist's XML serializer will scan all XML fragments for XInclude tags. Basically, the XInclude processor is implemented as a filter which sits between the serializer's output event stream and the receiver. If it finds an XInclude element, it will try to expand it. The current element in the stream is replaced by the result of the XInclude operation. XInclude processing is thus applied whenever eXist serializes an XML fragment, be it a document, the result of an XQuery or an XSLT stylesheet.

eXist's support for XInclude is not complete. You cannot include raw text, just XML. XPointers are restricted to XPath; the additional features defined in the XPointer spec (points and ranges) are not supported. Since version 1.2, the <xi:fallback> element is implemented properly.

Another common misunderstanding: eXist expands XIncludes at serialization time, which means that the query engine will see the XInclude tags before they are expanded. You cannot query across XIncludes - unless you create your own code (e.g. an XQuery function) for it. We would certainly like to support queries over xincluded content in the future though.

Why do we need XInclude? One reason is that eXist does not preserve entity declarations. Entities are resolved by the XML parser, so eXist just sees the expanded text, not the entity itself. However, external entities are handy if you want to include a given fragment at several locations in different files. For example, the navigation sidebar at the left will probably be used by several documents throughout a site, so it would be wise to keep it in an external file.

XInclude provides a powerful alternative. The following sections present some examples.

Note

If you came here from the examples page, you are already looking at a page that has been passed through XInclude, and you can see the live effect of all the examples below. If not, install the example data via the web admin interface, then browse to

rest/db/xinclude/xinclude.xml

and continue to read there.

By the way, this page also demonstrates some of the possibilities of eXist's REST interface. All the files required to render this page reside in the database and are read from there, including the logo and the two XSLT stylesheets used for the formatting.

1. Including a Document

To include an entire document, just specify its path in the href attribute of an <xi:include> tag. For example, the sidebar shown at the left of this documents has been included as follows:

<xi:include href="sidebar.html"/>

Please note that, as usual, you have to provide the correct namespace for XInclude, e.g. in the root element of the document. The official namespace is:

http://www.w3.org/2001/XInclude

2. Error Handling

An error will be generated if you try to (x)include a resource which does not exist. You can specify a fallback to avoid the error. The result of the XInclude will be the content of the <xi:fallback> element:

<xi:include href="unknown.html">
    <xi:fallback><p>Included document not found!</p></xi:fallback>
<xi:include>

See the result below:

                
                    

Included document not found!

3. Shorthand Pointer

The xpointer attribute is used to identify a portion of the resource to include. If the xpointer contains just a barename - called shorthand pointer - it will select the first element of the target document that has an attribute of type ID matching the name. For example, the following xinclude selects the p element from file disclaimer.xml, which has an ID attribute with value "statement".

<xi:include href="disclaimer.html" xpointer="statement"/>

The result of the XInclude will be displayed below:

                
					

For the XInclude examples to work, you need to install the sample documents. See admin app.

4. Selecting Fragments by an XPath Expression

We may also use an XPath expression to select fragments. The xpointer attribute contains an XPointer, which consists of so called "schemes". An XPath expression can be passed to the xpointer() XPointer scheme. The results of the expression will be included in place of the <xi:include> element. The following expression includes a section taken from Shakespeare's Macbeth:

<xi:include href="/db/shakespeare/plays/macbeth.html"
            xpointer="xpointer(//SPEECH[ngram:contains(SPEAKER, 'witch')][ft:query(., '"fenny snake"')])"/>

As before, the results are included below:

                
					
				
            

An XPath expression will be applied to the entire collection if the path in href points to a collection and not a single document:

<xi:include href="/db/shakespeare" xpointer="xpointer(//SPEECH[ft:query(., '"cursed spite"')])"/>
                
					
				
			

Concerning namespaces: all namespace/prefix mappings declared in the source document are passed to the query context. Alternatively, you may declare mappings with xmlns().

<xi:include href="disclaimer.html" xpointer="xpointer(//comment:comment)xmlns(t=http://nop.com)xmlns(comment=http://test.org)"/>
				
					

For the XInclude examples to work, you need to install the sample documents. See admin app.

5. Including the Results of a Stored XQuery

Another powerful feature: if the target of an XInclude reference points to an XQuery resource stored in the database (i.e. a binary resource with mime-type "application/xquery"), the XInclude processor will try to compile and execute this query. The root element included will be the root element returned by the XQuery script. For example:

<xi:include href="http://demo.exist-db.org/exist/display-collection.xq"/>

Calls a query without parameters. The result is shown below:

                
					

For the XInclude examples to work, you need to install the sample documents. See admin app.

The XInclude processor declares two variables in the XQuery's static context:

$xinclude:current-doc

the name of the document which (x)includes the query (without the collection path)

$xinclude:current-collection

the collection in which the current document resides

The example above uses xinclude:current-collection to determine the collection it should process. However, we can also pass explicit parameters to the XQuery:

<xi:include href="http://demo.exist-db.org/exist/testvars.xq?var1=Hello&var2=World"/>

The parameters var1 and var2 will be available to the XQuery as an external global variable. However, the XQuery needs to declare them or an error will be thrown:

declare variable $var1 external;
declare variable $var2 external;

The result of the call is included below:

                
					

For the XInclude examples to work, you need to install the sample documents. See admin app.

6. Including resources from external URIs or the file system

Beginning with version 1.3, if the URI in the href attribute specifies a known scheme (like http: or file:), eXist will try to load it as an external resource. For example:

<xi:include href="http://localhost:8080../rest/db/xinclude/disclaimer.xml"/>

Should load "disclaimer.xml" via HTTP (assuming that the URL is correct and you are using the default eXist setup):

				
    

The opinions presented herein represent those of the individual and should not be interpreted as the official policy endorsed by this organization.

This comment uses a different default namespace.

If no scheme is specified, the XInclude processor will first try to load the referenced document from the database (relative to the current collection), and if that fails: from the file system.

If the document that contains the xinclude has been constructed in an XQuery, relative file system paths will be resolved relative to the main XQuery module source file.

You can also use XPointers on external resources:

				<xi:include href="http://localhost:8080../rest/db/xinclude/disclaimer.xml"
					xpointer="xpointer(//comment:comment)xmlns(comment=http://test.org)"/>
			

again, the output of this is shown below:

				
					
				
			
Wolfgang M. Meier
wolfgang@exist-db.org