Xml configuration files inheritance

From FVue
Jump to: navigation, search

How can I have multiple XML configuration files, with precedence and inheritance?

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

Merging XML Documents

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.

Comments

blog comments powered by Disqus