Xml configuration files inheritance
How can I have multiple XML configuration files, with precedence and inheritance?
Contents
Solution
+------------+ +-----------+ | parent.xml | | child.xml | +------+-----+ +-----+-----+ /_\ /_\ | | +------+------+ | +----+----+ | all.xml | +---------+
With XInclude
Advantages of XInclude are each XML document stand on its own, allowing each document its own entities.
parent.xml <?xml version="1.0"?> <conf> <array> <key1>value1</key1> <key2>value2</key2> </array> </conf> child.xml <?xml version="1.0"?> <conf> <array> <key2>valueA</key2 <key3>value3</key3> </array> </conf>
all.xml <?xml version="1.0"?> <all xmlns:xi="http://www.w3.org/2003/XInclude"> <xi:include href="child.xml"/> <xi:include href="parent.xml"/> </all>
Without XInclude
all.xml <?xml version="1.0"?> <!DOCTYPE [ <!ENTITY child SYSTEM "parent.xml"> <!ENTITY parent SYSTEM "child.xml"> <all> &child; &parent; </all>
XSLT
Now XSLT will automatically return the first found value, with child.xml having precedence:
<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/all"> <xsl:value-of select="conf/array/key2"/> </xsl:template> </xsl:stylesheet>
Or when using XMLStarlet Command Line XML Toolkit:
# With XInclude xmllint --xinclude all.xml | xml sel -t -m /all -v conf/array/key2 # Without XInclude xml sel -t -m /all -v conf/array/key2 all.xml
So in fact child.xml inherits all its values from parent.xml :-) with one caveat: When selecting the entire array, like this:
xml sel -t -m /all -v conf/array
XSLT will return the array of child.xml, leaving out key1 of parent.xml.
Road
20051128
Gregory V. Wilson: "It's the XML Configuration File's Fault"
"And, on another note, mayb e its time for a Config service that just doles out java config objects registered against a name ( maybe JNDI ). ConfigLoaders can populate these from many data stores, including the command line, XML files, property files, DBMS's, serialized objects, YAML, jython/jruby etc.
One of the cooler hacks I saw for using XML config in your own app was to register an XSLT extension function which called Config object methods to populate a Configuration. Nice, no boilerplate code, very flexible." – Lyndon Samson
This solution Merging two XML Documents appends string values, whereas I want them to be separate elements.
Another solution would be to put the entities in a separate file, but still the merging would be 1-dimensional:
+------------+ +---------+ +-----------+ | parent.xml | | all.xml | | child.xml | +----------+-+ +--+---+--+ +-+---------+ | / \ | +--+-------+-+ +-+-------+-+ | parent.ent | | child.ent | +------------+ +-----------+
With the files containing:
parent.xml <?xml version="1.0"?> <!DOCTYPE [<!ENTITY parent SYSTEM "parent.ent">]> <root>&parent;</root> child.xml <?xml version="1.0"?> <!DOCTYPE [<!ENTITY child SYSTEM "child.ent">]> <root>&child;</root> parent.ent <key1>value1</key1> <key2>value2</key2> child.ent <key2>valueA</key2 <key3>value3</key3> all.xml <?xml version="1.0"?> <!DOCTYPE [ <!ENTITY child SYSTEM "child.ent"> <!ENTITY parent SYSTEM "parent.ent"> <root> &child; &parent; </root>
The value-with-precedence can than be acquired by XSLT by selecting the first encountered key: <xsl:value-of select="key2[1]">
This mail archive directed me to xmllint.