eXist-db comes with partial support for the XInclude standard. By default, eXist-db's XML serializer will scan all XML fragments for XInclude tags.
The XInclude processor is implemented as a filter in between the serializer's output event stream and the receiver. If it finds an XInclude element, it will try to expand it. XInclude processing is therefore applied whenever eXist-db serializes an XML fragment,whether it's a document, the result of an XQuery or an XSLT stylesheet.
eXist-db's does not support the full XInclude standard:
You cannot include raw text, only XML.
XPointers are restricted to XPath. Additional features defined in the XPointer spec (points and locations) are not supported. However, you can use XPath functions to partly work around this and substitute XPointer's important
eXist-db expands XIncludes at serialization, which means that the query engine will see the XInclude tags before they are expanded. You therefore cannot query across XIncludes, unless you create your own code (e.g. an XQuery function) for it.
DTD entity declarations can be used for some of the things that XInclude can be used for. In general, however, XInclude is more powerful (with the exception that entity declarations are able include raw text).
The XInclude namespace (in the examples below bound to the prefix
Including entire documents
To include an entire document, simply specify its path in the
attribute of an
For example, one can include a standard disclaimer, stored in the file
short-disclaimer.xml, as follows:
If the URI in the
href attribute specifies a known scheme (like
file:), eXist-db will try to load it as an external
resource. For example:
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 (see Including XQuery results), relative file system paths will be resolved relative to the main XQuery module source file.
Selecting parts of a resource
xpointer attribute of the
<xi:include> element can be
used to identify which part of the resource to include.
Selection by identifier
If the XPointer contains a simple value it is interpreted as an identifier. This
will select the element in the target document that has a matching attribute of type
For example, assume an XInclude target document
<disclaimer> <p xml:id="p1"> First disclaimer ... </p> <p xml:id="p2"> Second disclaimer ... </p> </disclaimer>
the following XInclude selects the element from
identifier attribute with value
<xi:include href="disclaimer.xml" xpointer="p1"/>
When there are multiple instances of the same identifier attribute, only the first instance will be used.
Selecting by XPath expression
We can also use an XPath expression to select fragments. For this the
xpointer attribute must contain an XPointer, which consists of so
called "schemes". An XPath expression can be passed through the
xpointer() XPointer scheme.
The following expression includes the first stage direction in Shakespeare's Macbeth:
<xi:include href="/db/apps/demo/data/macbeth.xml" xpointer="xpointer(//PLAY/ACT/SCENE/STAGEDIR)"/>
Selecting by a search expression
XIncludes can also perform searches, for instance using a full-text search:
<xi:include href="/db/apps/demo/data/hamlet.xml" xpointer="xpointer(//SPEECH[ft:query(., '" slings="slings" and="and" arrows"')/LINE)"="arrows"')/LINE)""/>
The 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/apps/demo/data" xpointer="xpointer(//SPEECH[ft:query(., '"cursed spite"')]/LINE)"/>
In all cases, only the first hit is retrieved.
All namespace/prefix mappings declared in the source document are passed to the
query context. If necessary you can declare additional namespace mappings using
xmlns(), like this:
<xi:include href="disclaimer.xml" xpointer="xpointer(//comment:comment) xmlns(comment=http://test.org)"/>
Including XQuery results
It is possible to include the result of an XQuery script by XInclude. If the target of
an XInclude reference points to an XQuery document stored in the database (binary
resource with MIME type
application/xquery), the XInclude processor will
attempt to compile and execute this query and use its results.
The XInclude processor declares two variables in the XQuery's static context:
The name of the document which XInclude-s the query (without its collection path)
the collection in which the current document resides
You can also pass additional parameters to the XQuery script:
var2 will be available
to the XQuery as an external global variable. The XQuery needs to declare them:
declare variable $var1 external; declare variable $var2 external;
An error is raised if you try to XInclude a resource which does not exist. You can
specify a fallback to avoid this. The result of the XInclude will be the content of the
<xi:include href="I-do-not exist.xml"> <xi:fallback> <p> The included document was not found! </p> </xi:fallback> <xi:include>
A fallback element itself cannot contain XInclude elements.
Implementing XPointer string-range()
One reason why the XPointer spec has hardly seen any implementation is that it
operates with "points" and "locations" which have no equivalent in the XPath Data Model.
However, a major use case for the XPointer specification is to allow pointing at a range
of characters inside an element. Luckily, we can work around the absence of this using
the XPath functions
In the following example, a range of characters in the text node of a
element is extracted, 20 characters long, starting at the 22nd character:
<xi:include href="/db/apps/demo/data" xpointer="xpointer( substring(string-join(//PLAY/ACT/SCENE/SPEECH/LINE,''), 22, 20) )"/>
Since only string contents is involved, these ranges can also work on text nodes belonging to different elements. In the following example, parts of succeeding lines are extracted from the SPEECH element:
<xi:include href="/db/apps/demo/data" xpointer="xpointer( substring(string-join(//PLAY/ACT/SCENE/SPEECH, ''), 202, 24) )"/>