XInclude standards version 1.0 and 1.1
https://www.w3.org/TR/xinclude/
https://www.w3.org/TR/xinclude-11/
have not been implemented widely due to their complexity.
They are not supported by DataPower, see "Supported standards and protocols" of release notes:
https://www.ibm.com/support/knowledgecenter/SS9H2Y_7.5.0/com.ibm.dp.doc/releasenotes.html#relnotes__standards
In developerWorks DataPower forum posting customer asked how to deal with them.
Despite saying just "not supported", I mentioned that a service implementing XInclude could help in cases where a URL is needed that should specify a XML file -- just reference the service, and that will return the expanded XML.
So this blog posting is on stylesheet xinclude.xsl I have implemented to do simple XInclude processing with depth/loop protection.
Why simple? The only feature implemented is following the "href" attribute, but either that's already OK for you, or you can use xinclude.xsl as starting point and add other spec features.
Here are customer sample XML files:
💻 cat AAA.xml
<AAAInfo xmlns="http://www.datapower.com/AAAInfo" xmlns:xi="http://www.w3.org/2001/XInclude">
<FormatVersion>1</FormatVersion>
<xi:include href="MasterAAA.xml"/>
</AAAInfo>
💻
💻 cat MasterAAA.xml
<Authenticate>
<Username>abcd</Username>
<Password>abcd</Password>
<OutputCredential>guest</OutputCredential>
</Authenticate>
💻
And here you can see that DataPower XSLT processor can process the <xi:include>:
💻 xj xinclude.xsl AAA.xml ; echo
<AAAInfo xmlns="http://www.datapower.com/AAAInfo" xmlns:xi="http://www.w3.org/2001/XInclude">
<FormatVersion>1</FormatVersion>
<Authenticate xmlns="">
<Username>abcd</Username>
<Password>abcd</Password>
<OutputCredential>guest</OutputCredential>
</Authenticate>
</AAAInfo>
💻
So you just create eg. a loopback XML Firewall service on DataPower, add a Fetch action for your top XML file, and a Transform action with xinclude.xsl. That's all. Here is the stylesheet:
https://stamm-wilbrandt.de/en/blog/xinclude.xsl
💻 cat xinclude.xsl
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output omit-xml-declaration="yes" />
<xsl:template match="*[local-name()='include' and namespace-uri()=$xinc-ns]">
<xsl:param name="L" select="$maxL"/>
<xsl:if test="$L < 1"><xsl:message terminate="yes"/></xsl:if>
<xsl:apply-templates select="document(@href)">
<xsl:with-param name="L" select="$L - 1"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="* | comment() | processing-instruction()">
<xsl:param name="L" select="$maxL"/>
<xsl:if test="$L < 1"><xsl:message terminate="yes"/></xsl:if>
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates select="node()">
<xsl:with-param name="L" select="$L"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:variable name="maxL" select="5"/>
<xsl:variable name="xinc-ns" select="$xinc/ns"/>
<xsl:variable name="xinc">
<ns>http://www.w3,org/1999/XML/xinclude</ns>
<ns>http://www.w3.org/2001/XInclude</ns>
</xsl:variable>
</xsl:stylesheet>
💻
Some comments:
- the template parameter "L" is used to prevent following loops endlessly, or XIncludes that are too deep
- you may want to add a message text, the empty <xsl:message> is used to immediately terminate stylesheet execution (maximal inclusion level)
- xinc-ns variable definition is the simplest way I know of to instantiate a nodeset
- DataPower XSLT compiler does not distinct RTF (Result Tree Fragment) and XML tree, so for other XSLT processors use of exslt:node-set() may be needed
- xinc variable allows you to list all XInclude namespaces that you want to work
- comparison of namespace-uri() with $xinc-ns works nicely (comparison of string and nodeset)
Hermann.