Using xinclude in config files
starksm64 Mar 3, 2007 12:43 PMSomething I have been meaning to look at for a while now is whether we could use xinclude processing to allow the default dist config files to remain untouched by users. It seems to work as expected and can be used for this, but we need to make some changes to fully support it. First, a little testcase to illustrate some xinclude behaviors:
package xml.xinclude; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilder; import org.junit.Test; import org.w3c.dom.Document; import org.w3c.dom.ls.DOMImplementationLS; import org.w3c.dom.ls.LSSerializer; /** * Basic tests of xinclude behavior. * @author Scott.Stark@jboss.org * @version $Revision:$ */ public class XIncludeTests { @Test public void testInclude() throws Exception { Document doc = getDocument("testInclude.xml"); printDoc(doc); } @Test public void testIncludeFallback() throws Exception { Document doc = getDocument("testIncludeFallback.xml"); printDoc(doc); } @Test public void testIncludeFallbackNoBaseUri() throws Exception { Document doc = getDocument("testIncludeFallback.xml", "http://apache.org/xml/features/xinclude/fixup-base-uris", false); printDoc(doc); } Document getDocument(String name) throws Exception { return getDocument(name, null, false); } Document getDocument(String name, String feature, boolean flag) throws Exception { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); dbf.setXIncludeAware(true); if (feature != null) { dbf.setFeature(feature, flag); } DocumentBuilder builder = dbf.newDocumentBuilder(); InputStream is = getResource(name); Document doc = builder.parse(is); is.close(); return doc; } InputStream getResource(String name) throws IOException { InputStream is = getClass().getResourceAsStream(name); if (is == null) throw new FileNotFoundException(name); return is; } void printDoc(Document doc) { DOMImplementationLS ls = (DOMImplementationLS) doc.getImplementation() .getFeature("LS", "3.0"); LSSerializer serializer = ls.createLSSerializer(); System.out.println(serializer.writeToString(doc)); } }
testInclude.xml:
<?xml version="1.0" encoding="UTF-8"?> <a name="a-name"> <xi:include href="b.xml" xml:base="/home/starksm/java/workspace/JavaTests/src/xml/xinclude/" xmlns:xi="http://www.w3.org/2001/XInclude"/> </a>
b.xml:
<?xml version="1.0" encoding="UTF-8"?> <b name="b-name"> <c name="c-name" /> </b>
testIncludeFallback.xml:
<?xml version="1.0" encoding="UTF-8"?> <a name="a-name"> <xi:include href="b.xml" xmlns:xi="http://www.w3.org/2001/XInclude"> <xi:fallback> <b name="fallback-b"> <c name="fallback-c" /> </b> </xi:fallback> </xi:include> </a>
The resulting dom for the 3 tests are,
testInclude:
<?xml version="1.0" encoding="UTF-16"?> <a name="a-name"> <b name="b-name" xml:base="/home/starksm/java/workspace/JavaTests/src/xml/xinclude/b.xml"> <c name="c-name"/> </b> </a>
testIncludeFallback:
<?xml version="1.0" encoding="UTF-16"?> <a name="a-name"> <b name="fallback-b" xml:base="" xmlns:xi="http://www.w3.org/2001/XInclude"> <c name="fallback-c"/> </b> </a>
testIncludeFallbackNoBaseUri:
<?xml version="1.0" encoding="UTF-16"?> <a name="a-name"> <b name="fallback-b" xmlns:xi="http://www.w3.org/2001/XInclude"> <c name="fallback-c"/> </b> </a>
The changes needed are:
1. Come up with a convention of xml:base location and href to define where overriden config files go by default, and how the override files are names.
2. Incorporate xinclude statements in the config files with fallbacks that correspond to the default out of the box configuration. For some config files we may want the xinclude statements on a per bean level, while others (jms destinations as an example) may only want an include on the root element.
3. Enable xinclude processing on the dom/sax factories. If you don't call setXIncludeAware on the parser factory the xinclude statements are just passed through as is.
4. Either rewrite the schemas/dtds to allow for xml:base in elements that are included, or be able to disable the base URI fixup as specified by the XInclude Recommendation.
The profileservice removes the need for this, but until all managable content is editable via the profileservice, there still is a need for better override support, as well as the cases where a full featured profileservice is not being used.