Say I have a source XML document that uses XIncludes, like this:
<?xml version="1.0" encoding="UTF-8"?>
<parent xmlns:xi="http://www.w3.org/2001/XInclude" xml:id="parent01">
<xi:include href="child01.xml"/>
<xi:include href="child02.xml"/>
<xi:include href="child03.xml"/>
</parent>
The three further XML documents it calls in XIncludes look like this:
child01.xml:
<?xml version="1.0" encoding="UTF-8"?>
<children>
<child xml:id="child01">
<p>This is child 1.</p>
</child>
</children>
child02.xml:
<?xml version="1.0" encoding="UTF-8"?>
<children>
<child xml:id="child02">
<p>This is child 2.</p>
</child>
</children>
child03.xml:
<?xml version="1.0" encoding="UTF-8"?>
<children>
<child xml:id="child03">
<p>This is child 3.</p>
</child>
</children>
I have an XSLT 2.0 transform like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates select="parent"/>
</xsl:template>
<xsl:template match="parent">
<volume>
<xsl:apply-templates select="@*|.//child"/>
</volume>
</xsl:template>
<xsl:template match="child">
<chapter>
<xsl:apply-templates select="@*|*|text()"/>
</chapter>
</xsl:template>
<xsl:template match="@*|*|text()">
<xsl:copy copy-namespaces="no">
<xsl:apply-templates select="@*|*|text()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When all the files referenced by XIncludes are present in the same folder as parent01.xml, my transform works just fine, and produces this output:
<?xml version="1.0" encoding="UTF-8"?>
<volume xml:id="parent01">
<chapter xml:id="child01">
<p>This is child 1.</p>
</chapter>
<chapter xml:id="child02">
<p>This is child 2.</p>
</chapter>
<chapter xml:id="child03">
<p>This is child 3.</p>
</chapter>
</volume>
However, if one file – say, child02.xml – is missing, the transform fails.
This failure would have been prevented if parent01.xml had included xi:fallback elements, like this:
<?xml version="1.0" encoding="UTF-8"?>
<parent xmlns:xi="http://www.w3.org/2001/XInclude" xml:id="parent01">
<xi:include href="child01.xml">
<xi:fallback>
<child>
<p>The file is missing.</p>
</child>
</xi:fallback>
</xi:include>
<xi:include href="child02.xml">
<xi:fallback>
<child>
<p>The file is missing.</p>
</child>
</xi:fallback>
</xi:include>
<xi:include href="child03.xml">
<xi:fallback>
<child>
<p>The file is missing.</p>
</child>
</xi:fallback>
</xi:include>
</parent>
Then, the output would have been as follows:
<?xml version="1.0" encoding="UTF-8"?>
<volume xml:id="parent01">
<chapter xml:id="child01">
<p>This is child 1.</p>
</chapter>
<chapter>
<p>The file is missing.</p>
</chapter>
<chapter xml:id="child03">
<p>This is child 3.</p>
</chapter>
</volume>
My question is this: is it possible to write my XSLT transform to insert an instance of xi:fallback into every xi:include before processing the XInclude – that is, to add a default xi:fallback instance where none is present, and then process the XInclude as if that xi:fallback instance had been present?
Thank you for any advice anyone can offer.