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.
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
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.
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:
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:
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:
See the result below:
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".
The result of the XInclude will be displayed below:
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:
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:
Concerning namespaces: all namespace/prefix mappings declared in the source document are passed to the query context. Alternatively, you may declare mappings with xmlns().
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:
Calls a query without parameters. The result is shown below:
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:
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:
The result of the call is included below: