You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by oh...@apache.org on 2014/06/08 20:24:00 UTC
svn commit: r1601237 - in
/commons/proper/configuration/trunk/src/site/xdoc/userguide: howto_xml.xml
user_guide.xml
Author: oheger
Date: Sun Jun 8 18:23:59 2014
New Revision: 1601237
URL: http://svn.apache.org/r1601237
Log:
Removed documentation extracted to another chapter from howto_xml.
Also wrote a short introduction.
Modified:
commons/proper/configuration/trunk/src/site/xdoc/userguide/howto_xml.xml
commons/proper/configuration/trunk/src/site/xdoc/userguide/user_guide.xml
Modified: commons/proper/configuration/trunk/src/site/xdoc/userguide/howto_xml.xml
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/site/xdoc/userguide/howto_xml.xml?rev=1601237&r1=1601236&r2=1601237&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/site/xdoc/userguide/howto_xml.xml (original)
+++ commons/proper/configuration/trunk/src/site/xdoc/userguide/howto_xml.xml Sun Jun 8 18:23:59 2014
@@ -19,1035 +19,22 @@
<document>
<properties>
- <title>Hierarchical configurations and XML Howto</title>
- <author email="oheger@apache.org">Oliver Heger</author>
+ <title>XML Configurations</title>
</properties>
<body>
- <section name="Hierarchical Configurations">
+ <section name="XML Configurations">
<p>
- Many sources of configuration data have a hierarchical or tree-like
- nature. They can represent data that is structured in many ways.
- Such configuration sources are represented by classes implementing the
- <code><a href="../apidocs/org/apache/commons/configuration/HierarchicalConfiguration.html">
- HierarchicalConfiguration</a></code> interface. With
- <code><a href="../apidocs/org/apache/commons/configuration/BaseHierarchicalConfiguration.html">
- BaseHierarchicalConfiguration</a></code> there is a fully functional
- implementation of the interface from which most of the hierarchical
- configuration classes shipped with <em>Commons Configuration</em> are
- derived.
- </p>
- <p>
- Prominent examples of hierarchical configuration sources are XML
- documents. They can be read and written using the
+ An important sub category of hierarchical configurations files are XML
+ documents. <em>Commons Configuration</em> ships with the
<code><a href="../apidocs/org/apache/commons/configuration/XMLConfiguration.html">
- XMLConfiguration</a></code> class. This section explains how
- to deal with such structured data and demonstrates the enhanced query
- facilities supported by <code>HierarchicalConfiguration</code>. We
- use XML documents as examples for structured configuration sources,
- but the information provided here (especially the rules for accessing
- properties) applies to other hierarchical configurations as well.
- Examples for other hierarchical configuration classes are
- <ul>
- <li><code><a href="../apidocs/org/apache/commons/configuration/CombinedConfiguration.html">
- CombinedConfiguration</a></code></li>
- <li><code><a href="../apidocs/org/apache/commons/configuration/INIConfiguration.html">
- INIConfiguration</a></code></li>
- <li><code><a href="../apidocs/org/apache/commons/configuration/plist/PropertyListConfiguration.html">
- PropertyListConfiguration</a></code></li>
- </ul>
- </p>
-
- <subsection name="Accessing properties in hierarchical configurations">
- <p>
- We will start with a simple XML document to show some basics
- about accessing properties. The following file named
- <code>gui.xml</code> is used as example document:
- </p>
-<source><![CDATA[
-<?xml version="1.0" encoding="ISO-8859-1" ?>
-<gui-definition>
- <colors>
- <background>#808080</background>
- <text>#000000</text>
- <header>#008000</header>
- <link normal="#000080" visited="#800080"/>
- <default>${colors.header}</default>
- </colors>
- <rowsPerPage>15</rowsPerPage>
- <buttons>
- <name>OK</name>
- <name>Cancel</name>
- <name>Help</name>
- </buttons>
- <numberFormat pattern="###,###.##"/>
-</gui-definition>
-]]></source>
- <p>
- (As becomes obvious, this tutorial does not bother with good
- design of XML documents, the example file should rather
- demonstrate the different ways of accessing properties.)
- To access the data stored in this document it must be loaded
- by <code><a href="../apidocs/org/apache/commons/configuration/XMLConfiguration.html">
- XMLConfiguration</a></code>. Like for other
- <a href="howto_filebased.html">file-based</a> configuration classes
- a <code><a href="../apidocs/org/apache/commons/configuration/builder/FileBasedConfigurationBuilder.html">
- FileBasedConfigurationBuilder</a></code> is used for reading the source
- file as shown in the following code fragement:
- </p>
-<source><![CDATA[
-Parameters params = new Parameters();
-FileBasedConfigurationBuilder<XMLConfiguration> builder =
- new FileBasedConfigurationBuilder<XMLConfiguration>(XMLConfiguration.class)
- .configure(params.xml()
- .setFileName("gui.xml"));
-try
-{
- XMLConfiguration config = builder.getConfiguration();
- ...
-}
-catch(ConfigurationException cex)
-{
- // loading of the configuration file failed
-}
-]]></source>
- <p>
- If no exception was thrown, the properties defined in the
- XML document are now available in the configuration object.
- Other hierarchical configuration classes that operate on files can be
- loaded in an analogous way. The following fragment shows how the
- properties in the configuration object can be accessed:
- </p>
-<source><![CDATA[
-String backColor = config.getString("colors.background");
-String textColor = config.getString("colors.text");
-String linkNormal = config.getString("colors.link[@normal]");
-String defColor = config.getString("colors.default");
-int rowsPerPage = config.getInt("rowsPerPage");
-List<Object> buttons = config.getList("buttons.name");
-]]></source>
- <p>
- This listing demonstrates some important points about constructing the
- keys for accessing properties in hierarchical configuration sources and about
- features of <code>HierarchicalConfiguration</code> in general:
- <ul>
- <li>
- Nested elements are accessed using a dot notation. In
- the example document there is an element <code><text></code>
- in the body of the <code><color></code> element. The
- corresponding key is <code>color.text</code>.
- </li>
- <li>
- The root element is ignored when constructing keys. In
- the example you do not write <code>gui-definition.color.text</code>,
- but only <code>color.text</code>.
- </li>
- <li>
- Attributes of XML elements are accessed in a XPath like notation.
- </li>
- <li>
- <a href="howto_basicfeatures.html#Variable_Interpolation">Interpolation</a>
- can be used in the same way as for all other standard configuration
- implementations. Here the <code><default></code> element in the
- <code>colors</code> section refers to another color.
- </li>
- <li>
- Lists of properties can be defined by just repeating elements.
- In this example the <code>buttons.name</code> property
- has the three values <em>OK</em>, <em>Cancel</em>, and
- <em>Help</em>, so it is queried using the <code>getList()</code>
- method. This works with attributes, too. In addition, a special
- <code><a href="../apidocs/org/apache/commons/configuration/convert/ListDelimiterHandler.html">
- ListDelimiterHandler</a></code> implementation can be set which
- supports splitting texts at a specific list delimiter character. This
- works in the same way as described in the section about
- <a href="howto_properties.html#Lists_and_arrays">properties
- configuration</a>. If this mode was used, the three button names could
- be defined in a single XML element. However, then the <em>pattern</em>
- attribute of the <code><numberFormat></code> element needs to
- escape the list delimiter which occurs in its content using a
- backslash character. With these changes the affected part of the XML
- document would look as follows:
-<source><![CDATA[
- <buttons>
- <name>OK, Cancel, Help</name>
- </buttons>
- <numberFormat pattern="###\,###.##"/>
-]]></source>
- Because repeating elements is a natural pattern for XML documents
- using list splitting is rather untypical for this format.
- </li>
- </ul>
- </p>
- <p>
- The next section will show how data in a more complex XML
- document can be processed.
+ XMLConfiguration</a></code> class that can read and write files of this
+ type. All features described in the chapter about
+ <a href="howto_hierarchical.html">Hierarchical Configurations</a> are
+ supported by XML configurations as well. In this chapter the additional
+ functionality offered by the <code>XMLConfiguration</code> class is
+ discussed.
</p>
- </subsection>
-
- <subsection name="Complex hierarchical structures">
- <p>
- Consider the following scenario: An application operates on
- database tables and wants to load a definition of the database
- schema from its configuration. A XML document provides this
- information. It could look as follows:
- </p>
- <source><![CDATA[
-<?xml version="1.0" encoding="ISO-8859-1" ?>
-
-<database>
- <tables>
- <table tableType="system">
- <name>users</name>
- <fields>
- <field>
- <name>uid</name>
- <type>long</type>
- </field>
- <field>
- <name>uname</name>
- <type>java.lang.String</type>
- </field>
- <field>
- <name>firstName</name>
- <type>java.lang.String</type>
- </field>
- <field>
- <name>lastName</name>
- <type>java.lang.String</type>
- </field>
- <field>
- <name>email</name>
- <type>java.lang.String</type>
- </field>
- </fields>
- </table>
- <table tableType="application">
- <name>documents</name>
- <fields>
- <field>
- <name>docid</name>
- <type>long</type>
- </field>
- <field>
- <name>name</name>
- <type>java.lang.String</type>
- </field>
- <field>
- <name>creationDate</name>
- <type>java.util.Date</type>
- </field>
- <field>
- <name>authorID</name>
- <type>long</type>
- </field>
- <field>
- <name>version</name>
- <type>int</type>
- </field>
- </fields>
- </table>
- </tables>
-</database>
-]]></source>
- <p>
- This XML is quite self explanatory; there is an arbitrary number
- of table elements, each of it has a name and a list of fields.
- A field in turn consists of a name and a data type. This
- XML document (let's call it <code>tables.xml</code>) can be
- loaded in exactly the same way as the simple document in the
- section before.
- </p>
- <p>
- When we now want to access some of the properties we face a
- problem: the syntax for constructing configuration keys we
- learned so far is not powerful enough to access all of the data
- stored in the tables document.
- </p>
- <p>
- Because the document contains a list of tables some properties
- are defined more than once. E.g. the configuration key
- <code>tables.table.name</code> refers to a <code>name</code>
- element inside a <code>table</code> element inside a
- <code>tables</code> element. This constellation happens to
- occur twice in the tables document.
- </p>
- <p>
- Multiple definitions of a property do not cause problems and are
- supported by all classes of Configuration. If such a property
- is queried using <code>getProperty()</code>, the method
- recognizes that there are multiple values for that property and
- returns a collection with all these values. So we could write
- </p>
- <source><![CDATA[
-Object prop = config.getProperty("tables.table.name");
-if(prop instanceof Collection)
-{
- System.out.println("Number of tables: " + ((Collection<?>) prop).size());
-}
-]]></source>
- <p>
- An alternative to this code would be the <code>getList()</code>
- method of <code>Configuration</code>. If a property is known to
- have multiple values (as is the table name property in this example),
- <code>getList()</code> allows retrieving all values at once.
- <b>Note:</b> it is legal to call <code>getString()</code>
- or one of the other getter methods on a property with multiple
- values; it returns the first element of the list.
- </p>
- </subsection>
- <subsection name="Accessing structured properties">
- <p>
- Okay, we can obtain a list with the names of all defined
- tables. In the same way we can retrieve a list with the names
- of all table fields: just pass the key
- <code>tables.table.fields.field.name</code> to the
- <code>getList()</code> method. In our example this list
- would contain 10 elements, the names of all fields of all tables.
- This is fine, but how do we know, which field belongs to
- which table?
- </p>
- <p>
- When working with such hierarchical structures the configuration keys
- used to query properties can have an extended syntax. All components
- of a key can be appended by a numerical value in parentheses that
- determines the index of the affected property. So if we have two
- <code>table</code> elements we can exactly specify, which one we
- want to address by appending the corresponding index. This is
- explained best by some examples:
- </p>
- <p>
- We will now provide some configuration keys and show the results
- of a <code>getProperty()</code> call with these keys as arguments.
- <dl>
- <dt><code>tables.table(0).name</code></dt>
- <dd>
- Returns the name of the first table (all indices are 0 based),
- in this example the string <em>users</em>.
- </dd>
- <dt><code>tables.table(0)[@tableType]</code></dt>
- <dd>
- Returns the value of the tableType attribute of the first
- table (<em>system</em>).
- </dd>
- <dt><code>tables.table(1).name</code></dt>
- <dd>
- Analogous to the first example returns the name of the
- second table (<em>documents</em>).
- </dd>
- <dt><code>tables.table(2).name</code></dt>
- <dd>
- Here the name of a third table is queried, but because there
- are only two tables result is <b>null</b>. The fact that a
- <b>null</b> value is returned for invalid indices can be used
- to find out how many values are defined for a certain property:
- just increment the index in a loop as long as valid objects
- are returned.
- </dd>
- <dt><code>tables.table(1).fields.field.name</code></dt>
- <dd>
- Returns a collection with the names of all fields that
- belong to the second table. With such kind of keys it is
- now possible to find out, which fields belong to which table.
- </dd>
- <dt><code>tables.table(1).fields.field(2).name</code></dt>
- <dd>
- The additional index after field selects a certain field.
- This expression represents the name of the third field in
- the second table (<em>creationDate</em>).
- </dd>
- <dt><code>tables.table.fields.field(0).type</code></dt>
- <dd>
- This key may be a bit unusual but nevertheless completely
- valid. It selects the data types of the first fields in all
- tables. So here a collection would be returned with the
- values [<em>long, long</em>].
- </dd>
- </dl>
- </p>
- <p>
- These examples should make the usage of indices quite clear.
- Because each configuration key can contain an arbitrary number
- of indices it is possible to navigate through complex structures of
- hierarchical configurations; each property can be uniquely identified.
- </p>
- </subsection>
-
- <subsection name="Sub Configurations">
- <p>
- Sometimes dealing with long property keys may become inconvenient,
- especially if always the same properties are accessed. For this
- case <code>HierarchicalConfiguration</code> provides a short cut
- with the <code>configurationAt()</code> method. This method can
- be passed a key that selects exactly one node of the hierarchy
- of nodes contained in a hierarchical configuration. Then a new
- hierarchical configuration will be returned whose root node is
- the selected node. So all property keys passed into that
- configuration should be relative to the new root node. For
- instance, if we are only interested in information about the
- first database table, we could do something like that:
- </p>
-<source><![CDATA[
-HierarchicalConfiguration<ImmutableNode> sub = config.configurationAt("tables.table(0)");
-String tableName = sub.getString("name"); // only need to provide relative path
-List<Object> fieldNames = sub.getList("fields.field.name");
-]]></source>
- <p>
- For dealing with complex list-like structures there is another
- short cut. Often it will be necessary to iterate over all items
- in the list and access their (sub) properties. A good example are
- the fields of the tables in our demo configuration. When you want
- to process all fields of a table (e.g. for constructing a
- <code>CREATE TABLE</code> statement), you will need all information
- stored for them in the configuration. An option would be to use
- the <code>getList()</code> method to fetch the required data one
- by one:
- </p>
-<source><![CDATA[
-List<Object> fieldNames = config.getList("tables.table(0).fields.field.name");
-List<Object> fieldTypes = config.getList("tables.table(0).fields.field.type");
-List<Object> ... // further calls for other data that might be stored in the config
-]]></source>
- <p>
- But this is not very readable and will fail if not all field
- elements contain the same set of data (for instance the
- <code>type</code> property may be optional, then the list for
- the types can contain less elements than the other lists). A
- solution to these problems is the <code>configurationsAt()</code>
- method, a close relative to the <code>configurationAt()</code>
- method covered above. This method evaluates the passed in key and
- collects all configuration nodes that match this criterion. Then
- for each node a <code>HierarchicalConfiguration</code> object is
- created with this node as root node. A list with these configuration
- objects is returned. As the following example shows this comes in
- very handy when processing list-like structures:
- </p>
-<source><![CDATA[
-List<HierarchicalConfiguration<ImmutableNode>> fields =
- config.configurationsAt("tables.table(0).fields.field");
-for(HierarchicalConfiguration sub : fields)
-{
- // sub contains all data about a single field
- String fieldName = sub.getString("name");
- String fieldType = sub.getString("type");
- ...
-]]></source>
- <p>
- Per default, the configurations returned by the <code>configurationAt()</code> and
- <code>configurationsAt()</code> methods are a kind of snapshots of
- the data stored in the original configuration. If the original
- configuration is later changed, these changes are not visible in the
- sub configuration and vice versa. If configuration settings just need
- to be read, this is fine.
- </p>
- <p>
- It is also possible to connect a sub configuration more directly to
- its original configuration. This is done by using overloaded versions
- of <code>configurationAt()</code> and <code>configurationsAt()</code>
- which accept an additional <strong>boolean</strong> parameter. If
- here the value <strong>true</strong> is passed, a special
- configuration implementation is returned (in fact, an instance of the
- <code><a href="../apidocs/org/apache/commons/configuration/SubnodeConfiguration.html">
- SubnodeConfiguration</a></code> class) that operates on the same
- data structures as the original configuration. Therefore, changes made
- on one configuration are directly reflected by the other one.
- </p>
- <p>
- Connecting a sub configuration with its parent configuration in the
- described way is useful in use cases in which configurations are
- updated. However, there can be pretty drastic updates which break
- such a connection. As an example, consider the case that a sub
- configuration is created for a certain sub tree of an original
- configuration. Now this sub tree gets removed from the original
- configuration. In this case, the sub configuration becomes detached
- from its parent. Its content is not changed, but it is now again like
- a snapshot or a copy of the original. This is demonstrated again in
- the following example:
-<source><![CDATA[
-// sub points to the 2nd table
-HierarchicalConfiguration<ImmutableNode> sub = config.configurationAt("tables.table(1)", true);
-assertEquals("documents", sub.getString("name"));
-
-// Now change name in parent configuration => should be visible in sub config
-config.setProperty("tables.table(1).name", "tasks");
-assertEquals("tasks", sub.getString("name"));
-
-// Clear the whole content of the 2nd table
-config.clearTree("tables.table(1)");
-// The key used to create the sub configuration is no longer valid,
-// so it is now detacted; it contains the recent data.
-assertEquals("tasks", sub.getString("name"));
-]]></source>
- </p>
- <p>
- This example uses the <code>clearTree()</code> method of
- <code>HierarchicalConfiguration</code> to remove all information
- about the second database table from the configuration data. While
- <code>clearProperty()</code> only removes the value of a property,
- <code>clearTree()</code> also removes all child elements and their
- children recursively. After this operation the key
- <em>tables.table(1)</em> specified when the sub configuration was
- created no longer points to an existing element; therefore, the
- sub configuration gets detached. Once detached, a sub configuration
- cannot be reconnected to its parent again. Even if another table
- element was added (making the sub key valid again), the sub
- configuration remains detached.
- </p>
- </subsection>
-
- <subsection name="Adding new properties">
- <p>
- So far we have learned how to use indices to avoid ambiguities when
- querying properties. The same problem occurs when adding new
- properties to a structured configuration. As an example let's
- assume we want to add a new field to the second table. New properties
- can be added to a configuration using the <code>addProperty()</code>
- method. Of course, we have to exactly specify where in the tree like structure new
- data is to be inserted. A statement like
- </p>
- <source><![CDATA[
-// Warning: This might cause trouble!
-config.addProperty("tables.table.fields.field.name", "size");
-]]></source>
- <p>
- would not be sufficient because it does not contain all needed
- information. How is such a statement processed by the
- <code>addProperty()</code> method?
- </p>
- <p>
- <code>addProperty()</code> splits the provided key into its
- single parts and navigates through the properties tree along the
- corresponding element names. In this example it will start at the
- root element and then find the <code>tables</code> element. The
- next key part to be processed is <code>table</code>, but here a
- problem occurs: the configuration contains two <code>table</code>
- properties below the <code>tables</code> element. To get rid off
- this ambiguity an index can be specified at this position in the
- key that makes clear, which of the two properties should be
- followed. <code>tables.table(1).fields.field.name</code> e.g.
- would select the second <code>table</code> property. If an index
- is missing, <code>addProperty()</code> always follows the last
- available element. In our example this would be the second
- <code>table</code>, too.
- </p>
- <p>
- The following parts of the key are processed in exactly the same
- manner. Under the selected <code>table</code> property there is
- exactly one <code>fields</code> property, so this step is not
- problematic at all. In the next step the <code>field</code> part
- has to be processed. At the actual position in the properties tree
- there are multiple <code>field</code> (sub) properties. So we here
- have the same situation as for the <code>table</code> part.
- Because no explicit index is defined the last <code>field</code>
- property is selected. The last part of the key passed to
- <code>addProperty()</code> (<code>name</code> in this example)
- will always be added as new property at the position that has
- been reached in the former processing steps. So in our example
- the last <code>field</code> property of the second table would
- be given a new <code>name</code> sub property and the resulting
- structure would look like the following listing:
- </p>
- <source><![CDATA[
- ...
- <table tableType="application">
- <name>documents</name>
- <fields>
- <field>
- <name>docid</name>
- <type>long</type>
- </field>
- <field>
- <name>name</name>
- <type>java.lang.String</type>
- </field>
- <field>
- <name>creationDate</name>
- <type>java.util.Date</type>
- </field>
- <field>
- <name>authorID</name>
- <type>long</type>
- </field>
- <field>
- <name>version</name>
- <name>size</name> <== Newly added property
- <type>int</type>
- </field>
- </fields>
- </table>
- </tables>
-</database>
-]]></source>
- <p>
- This result is obviously not what was desired, but it demonstrates
- how <code>addProperty()</code> works: the method follows an
- existing branch in the properties tree and adds new leaves to it.
- (If the passed in key does not match a branch in the existing tree,
- a new branch will be added. E.g. if we pass the key
- <code>tables.table.data.first.test</code>, the existing tree can be
- navigated until the <code>data</code> part of the key. From here a
- new branch is started with the remaining parts <code>data</code>,
- <code>first</code> and <code>test</code>.)
- </p>
- <p>
- If we want a different behavior, we must explicitely tell
- <code>addProperty()</code> what to do. In our example with the
- new field our intension was to create a new branch for the
- <code>field</code> part in the key, so that a new <code>field</code>
- property is added to the structure rather than adding sub properties
- to the last existing <code>field</code> property. This can be
- achieved by specifying the special index <code>(-1)</code> at the
- corresponding position in the key as shown below:
- </p>
- <source><![CDATA[
-config.addProperty("tables.table(1).fields.field(-1).name", "size");
-config.addProperty("tables.table(1).fields.field.type", "int");
-]]></source>
- <p>
- The first line in this fragment specifies that a new branch is
- to be created for the <code>field</code> property (index -1).
- In the second line no index is specified for the field, so the
- last one is used - which happens to be the field that has just
- been created. So these two statements add a fully defined field
- to the second table. This is the default pattern for adding new
- properties or whole hierarchies of properties: first create a new
- branch in the properties tree and then populate its sub properties.
- As an additional example let's add a complete new table definition
- to our example configuration:
- </p>
- <source><![CDATA[
-// Add a new table element and define the name
-config.addProperty("tables.table(-1).name", "versions");
-
-// Add a new field to the new table
-// (an index for the table is not necessary because the latest is used)
-config.addProperty("tables.table.fields.field(-1).name", "id");
-config.addProperty("tables.table.fields.field.type", "int");
-
-// Add another field to the new table
-config.addProperty("tables.table.fields.field(-1).name", "date");
-config.addProperty("tables.table.fields.field.type", "java.sql.Date");
-...
-]]></source>
- <p>
- For more information about adding properties to a hierarchical
- configuration also have a look at the javadocs for
- <code><a href="../apidocs/org/apache/commons/configuration/HierarchicalConfiguration.html">
- HierarchicalConfiguration</a></code>.
- </p>
- </subsection>
- <subsection name="Escaping special characters">
- <p>
- Some characters in property keys or values require a special
- treatment.
- </p>
- <p>
- Per default the dot character is used as delimiter by most
- configuration classes (we will learn how to change this for
- hierarchical configurations in a later section). In some
- configuration formats however, dots can be contained in the
- names of properties. For instance, in XML the dot is a legal
- character that can occur in any tag. The same is true for the names
- of properties in windows ini files. So the following XML
- document is completely valid:
- </p>
- <source><![CDATA[
-<?xml version="1.0" encoding="ISO-8859-1" ?>
-
-<configuration>
- <test.value>42</test.value>
- <test.complex>
- <test.sub.element>many dots</test.sub.element>
- </test.complex>
-</configuration>
-]]></source>
- <p>
- This XML document can be loaded by <code>XMLConfiguration</code>
- without trouble, but when we want to access certain properties
- we face a problem: The configuration claims that it does not
- store any values for the properties with the keys
- <code>test.value</code> or <code>test.complex.test.sub.element</code>!
- </p>
- <p>
- Of course, it is the dot character contained in the property
- names, which causes this problem. A dot is always interpreted
- as a delimiter between elements. So given the property key
- <code>test.value</code> the configuration would look for an
- element named <code>test</code> and then for a sub element
- with the name <code>value</code>. To change this behavior it is
- possible to escape a dot character, thus telling the configuration
- that it is really part of an element name. This is simply done
- by duplicating the dot. So the following statements will return
- the desired property values:
- </p>
- <source><![CDATA[
-int testVal = config.getInt("test..value");
-String complex = config.getString("test..complex.test..sub..element");
-]]></source>
- <p>
- Note the duplicated dots whereever the dot does not act as
- delimiter. This way it is possible to access properties containing
- dots in arbitrary combination. However, as you can see, the
- escaping can be confusing sometimes. So if you have a choice,
- you should avoid dots in the tag names of your XML configuration
- files or other configuration sources.
- </p>
- </subsection>
- </section>
-
- <section name="Expression engines">
- <p>
- In the previous chapters we saw many examples about how properties
- in a <code>XMLConfiguration</code> object (or more general in a
- <code>HierarchicalConfiguration</code> object, because this is the
- base interface, which defines this functionality) can be queried or
- modified using a special syntax for the property keys. Well, this
- was not the full truth. Actually, property keys are not processed
- by the configuration object itself, but are delegated to a helper
- object, a so called <em>Expression engine</em>.
- </p>
- <p>
- The separation of the task of interpreting property keys into a
- helper object is a typical application of the <em>Strategy</em>
- design pattern. In this case it also has the advantage that it
- becomes possible to plug in different expression engines into a
- <code>HierarchicalConfiguration</code> object. So by providing
- different implementations of the
- <code><a href="../apidocs/org/apache/commons/configuration/tree/ExpressionEngine.html">
- ExpressionEngine</a></code>
- interface hierarchical configurations can support alternative
- expression languages for accessing their data.
- </p>
- <p>
- Before we discuss the available expression engines that ship
- with Commons Configuration, it should be explained how an
- expression engine can be associated with a configuration object.
- <code><a href="../apidocs/org/apache/commons/configuration/HierarchicalConfiguration.html">
- HierarchicalConfiguration</a></code> and all implementing classes
- provide a <code>setExpressionEngine()</code> method, which expects
- an implementation of the <code>ExpressionEngine</code> interface as
- argument. After this method was called, the configuration object will
- use the passed expression engine, which means that all property keys
- passed to methods like <code>getProperty()</code>,
- <code>getString()</code>, or <code>addProperty()</code> must
- conform to the syntax supported by this engine. Property keys
- returned by the <code>getKeys()</code> method will follow this
- syntax, too.
- </p>
- <p>
- The recommended approach is that a configuration object is fully
- initialized by the <a href="howto_builders.html">configuration
- builder</a> which creates it. The initialization parameters for
- hierarchical configurations allow setting the expression engine as
- shown in the following code fragment (more information about
- initialization parameters for hierarchical and XML configurations
- is provided in a later section in this chapter):
- </p>
-<source><![CDATA[
-Parameters params = new Parameters();
-FileBasedConfigurationBuilder<XMLConfiguration> builder =
- new FileBasedConfigurationBuilder<BaseHierarchicalConfiguration>(BaseHierarchicalConfiguration.class)
- .configure(params.hierarchical()
- .setExpressionEngine(new MyExpressionEngine()));
-]]></source>
- <p>
- Remember that it is possible to define
- <a href="howto_builders.html#Default_Initialization_Parameters">Default
- Initialization Parameters</a> for specific configuration classes.
- Using this mechanism, it is possible to instance to set a special
- expression engine for all XML configurations used by an
- application.
- </p>
-
- <subsection name="The default expression engine">
- <p>
- The syntax described so far for property keys of hierarchical
- configurations is implemented by a specific implementation of the
- <code><a href="../apidocs/org/apache/commons/configuration/tree/ExpressionEngine.html">
- ExpressionEngine</a></code> interface called
- <code><a href="../apidocs/org/apache/commons/configuration/tree/DefaultExpressionEngine.html">
- DefaultExpressionEngine</a></code>. An instance of this class
- is used by the base implementation of
- <code>HierarchicalConfiguration</code> if no specific expression
- engine was set (which is the reason why our examples above worked).
- </p>
- <p>
- After reading the examples of property keys provided so far in
- this document you should have a sound understanding regarding
- the features and the syntax supported by the
- <code>DefaultExpressionEngine</code> class. But it can do a
- little bit more for you: it defines a bunch of settings,
- which can be used to customize most tokens that can appear in a
- valid property key. You prefer curly brackets over paranthesis
- as index markers? You find the duplicated dot as escaped
- property delimiter counter-intuitive? Well, simply go ahead and
- change it! The following example shows how the syntax of a
- <code>DefaultExpressionEngine</code> object is modified. The
- key is to create an instance of the
- <code><a href="../apidocs/org/apache/commons/configuration/tree/DefaultExpressionEngineSymbols.html">
- DefaultExpressionEngineSymbols</a></code> class and to
- initialize it with the desired syntax elements. This is done
- using a builder approach:
- </p>
- <source><![CDATA[
-DefaultExpressionEngineSymbols symbols =
- new DefaultExpressionEngineSymbols.Builder(
- DefaultExpressionEngineSymbols.DEFAULT_SYMBOLS)
- // Use a slash as property delimiter
- .setPropertyDelimiter("/")
- // Indices should be specified in curly brackets
- .setIndexStart("{")
- .setIndexEnd("}")
- // For attributes use simply a @
- .setAttributeStart("@")
- .setAttributeEnd(null)
- // A Backslash is used for escaping property delimiters
- .setEscapedDelimiter("\\/")
- .create();
-
-// Now create a configuration using this expression engine
-Parameters params = new Parameters();
-FileBasedConfigurationBuilder<XMLConfiguration> builder =
- new FileBasedConfigurationBuilder<XMLConfiguration>(XMLConfiguration.class)
- .configure(params.xml()
- .setFileName("tables.xml")
- .setExpressionEngine(engine));
-XMLConfiguration config = builder.getConfiguration();
-
-// Access properties using the new syntax
-String tableName = config.getString("tables/table{0}/name");
-String tableType = config.getString("tables/table{0}@type");
- ]]></source>
- <p>
- <code>DefaultExpressionEngineSymbol</code> objects are
- immutable; the same is true for <code>DefaultExpressionEngine</code>.
- Thus a single expression engine instance can be shared between
- multiple configuration instances. The example fragment shows the
- typical usage pattern for constructing new
- <code>DefaultExpressionEngine</code> instances with an alternative
- syntax: A builder for a symbols object is constructed passing in
- an instance that serves as starting point - here the constant
- <code>DEFAULT_SYMBOLS</code> is used which defines the standard
- syntax. Then methods of the builder are used to modify only the
- settings which are to be adapted.
- </p>
- <p>
- <em>Tip:</em> Sometimes when processing an XML document you
- don't want to distinguish between attributes and "normal"
- child nodes. You can achieve this by setting the
- <code>AttributeEnd</code> property to <b>null</b> and the
- <code>AttributeStart</code> property to the same value as the
- <code>PropertyDelimiter</code> property. Then the syntax for
- accessing attributes is the same as the syntax for other
- properties:
- </p>
- <source><![CDATA[
-DefaultExpressionEngineSymbols symbolsNoAttributes =
- new DefaultExpressionEngineSymbols.Builder(
- DefaultExpressionEngineSymbols.DEFAULT_SYMBOLS)
- .setAttributeStart(
- DefaultExpressionEngineSymbols.DEFAULT_SYMBOLS.getPropertyDelimiter())
- .setAttributeEnd(null)
- .create();
-DefaultExpressionEngine engine = new DefaultExpressionEngine(symbolsNoAttributes);
-...
-Object value = config.getProperty("tables.table(0).name");
-// name can either be a child node of table or an attribute
- ]]></source>
- </subsection>
-
- <subsection name="The XPATH expression engine">
- <p>
- The expression language provided by the <code>DefaultExpressionEngine</code>
- class is powerful enough to address all properties in a
- hierarchical configuration, but it is not always convenient to
- use. Especially if list structures are involved, it is often
- necessary to iterate through the whole list to find a certain
- element.
- </p>
- <p>
- Think about our example configuration that stores information about
- database tables. A use case could be to load all fields that belong
- to the "users" table. If you knew the index of this
- table, you could simply build a property key like
- <code>tables.table(<index>).fields.field.name</code>,
- but how do you find out the correct index? When using the
- default expression engine, the only solution to this problem is
- to iterate over all tables until you find the "users"
- table.
- </p>
- <p>
- Life would be much easier if an expression language could be used,
- which would directly support queries of such kind. In the XML
- world, the XPATH syntax has grown popular as a powerful means
- of querying structured data. In XPATH a query that selects all
- field names of the "users" table would look something
- like <code>tables/table[@name='users']/fields/name</code> (here
- we assume that the table's name is modelled as an attribute).
- This is not only much simpler than an iteration over all tables,
- but also much more readable: it is quite obvious, which fields
- are selected by this query.
- </p>
- <p>
- Given the power of XPATH it is no wonder that we got many
- user requests to add XPATH support to <em>Commons Configuration</em>.
- Well, here is it!
- </p>
- <p>
- For enabling XPATH syntax for property keys you need the
- <code><a href="../apidocs/org/apache/commons/configuration/tree/xpath/XPathExpressionEngine.html">
- XPathExpressionEngine</a></code> class. This class
- implements the <code>ExpressionEngine</code> interface and can
- be plugged into a <code>HierarchicalConfiguration</code> object
- in the same way as described above. Because instances of
- <code>XPathExpressionEngine</code> are thread-safe and can be
- shared between multiple configuration objects it is also
- possible to set an instance as the default expression engine
- in the <a href="howto_builders.html#Default_Initialization_Parameters">
- default initialization parameters</a> for configuration
- builders, so that all hierarchical configuration
- objects make use of XPATH syntax. The following code fragment
- shows how XPATH support can be enabled for a configuration
- object:
- </p>
- <source><![CDATA[
-Parameters params = new Parameters();
-FileBasedConfigurationBuilder<XMLConfiguration> builder =
- new FileBasedConfigurationBuilder<XMLConfiguration>(XMLConfiguration.class)
- .configure(params.xml()
- .setFileName("tables.xml")
- .setExpressionEngine(new XPathExpressionEngine()));
-XMLConfiguration config = builder.getConfiguration();
-
-// Now we can use XPATH queries:
-List<Object> fields = config.getList("tables/table[1]/fields/name");
- ]]></source>
- <p>
- XPATH expressions are not only used for selecting properties
- (i.e. for the several getter methods), but also for adding new
- properties. For this purpose the keys passed into the
- <code>addProperty()</code> method must conform to a special
- syntax. They consist of two parts: the first part is an
- arbitrary XPATH expression that selects the node where the new
- property is to be added to, the second part defines the new
- element to be added. Both parts are separated by whitespace.
- </p>
- <p>
- Okay, let's make an example. Say, we want to add a <code>type</code>
- property under the first table (as a sibling to the <code>name</code>
- element). Then the first part of our key will have to select
- the first table element, the second part will simply be
- <code>type</code>, i.e. the name of the new property:
- </p>
- <source><![CDATA[
-config.addProperty("tables/table[1] type", "system");
- ]]></source>
- <p>
- (Note that indices in XPATH are 1-based, while in the default
- expression language they are 0-based.) In this example the part
- <code>tables/table[1]</code> selects the target element of the
- add operation. This element must exist and must be unique, otherwise an exception
- will be thrown. <code>type</code> is the name of the new element
- that will be added. If instead of a normal element an attribute
- should be added, the example becomes
- </p>
- <source><![CDATA[
-config.addProperty("tables/table[1] @type", "system");
- ]]></source>
- <p>
- It is possible to add complete paths at once. Then the single
- elements in the new path are separated by "/"
- characters. The following example shows how data about a new
- table can be added to the configuration. Here we use full paths:
- </p>
- <source><![CDATA[
-// Add new table "tasks" with name element and type attribute
-config.addProperty("tables table/name", "tasks");
-// last() selects the last element of this name,
-// which is the newest table element
-config.addProperty("tables/table[last()] @type", "system");
-
-// Now add fields
-config.addProperty("tables/table[last()] fields/field/name", "taskid");
-config.addProperty("tables/table[last()]/fields/field[last()] type", "int");
-config.addProperty("tables/table[last()]/fields field/name", "name");
-config.addProperty("tables/table[last()]/fields field/name", "startDate");
-...
- ]]></source>
- <p>
- The first line of this example adds the path <code>table/name</code>
- to the <code>tables</code> element, i.e. a new <code>table</code>
- element will be created and added as last child to the
- <code>tables</code> element. Then a new <code>name</code> element
- is added as child to the new <code>table</code> element. To this
- element the value "tasks" is assigned. The next line
- adds a <code>type</code> attribute to the new table element. To
- obtain the correct <code>table</code> element, to which the
- attribute must be added, the XPATH function <code>last()</code>
- is used; this function selects the last element with a given
- name, which in this case is the new <code>table</code> element.
- The following lines all use the same approach to construct a new
- element hierarchy: At first complete new branches are added
- (<code>fields/field/name</code>), then to the newly created
- elements further children are added.
- </p>
- <p>
- There is one gotcha with these keys described so far: they do
- not work with the <code>setProperty()</code> method! This is
- because <code>setProperty()</code> has to check whether the
- passed in key already exists; therefore it needs a key which can
- be interpreted by query methods. If you want to use
- <code>setProperty()</code>, you can pass in regular keys (i.e.
- without a whitespace separator). The method then tries to figure
- out which part of the key already exists in the configuration
- and adds new nodes as necessary. In principle such regular keys
- can also be used with <code>addProperty()</code>. However, they
- do not contain sufficient information to decide where new nodes
- should be added.
- </p>
- <p>
- To make this clearer let's go back to the example with the
- tables. Consider that there is a configuration which already
- contains information about some database tables. In order to add
- a new table element in the configuration
- <code>addProperty()</code> could be used as follows:
- </p>
- <source><![CDATA[
-config.addProperty("tables/table/name", "documents");
- ]]></source>
- <p>
- In the configuration a <code><tables></code> element
- already exists, also <code><table></code> and
- <code><name></code> elements. How should the expression
- engine know where new node structures are to be added? The
- solution to this problem is to provide this information in the
- key by stating:
- </p>
- <source><![CDATA[
-config.addProperty("tables table/name", "documents");
- ]]></source>
- <p>
- Now it is clear that new nodes should be added as children of
- the <code><tables></code> element. More information about
- keys and how they play together with <code>addProperty()</code>
- and <code>setProperty()</code> can be found in the Javadocs for
- <a href="../apidocs/org/apache/commons/configuration/tree/xpath/XPathExpressionEngine.html">
- <code>XPathExpressionEngine</code></a>.
- </p>
- <p>
- <em>Note:</em> XPATH support is implemented through
- <a href="http://commons.apache.org/jxpath">Commons JXPath</a>.
- So when making use of this feature, be sure you include the
- commons-jxpath jar in your classpath.
- </p>
- <p>
- In this tutorial we don't want to describe XPATH syntax and
- expressions in detail. Please refer to corresponding documentation.
- It is important to mention that by embedding Commons JXPath the
- full extent of the XPATH 1.0 standard can be used for constructing
- property keys.
- </p>
- </subsection>
</section>
<section name="Validation of XML configuration files">
Modified: commons/proper/configuration/trunk/src/site/xdoc/userguide/user_guide.xml
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/site/xdoc/userguide/user_guide.xml?rev=1601237&r1=1601236&r2=1601237&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/site/xdoc/userguide/user_guide.xml (original)
+++ commons/proper/configuration/trunk/src/site/xdoc/userguide/user_guide.xml Sun Jun 8 18:23:59 2014
@@ -97,6 +97,9 @@
<li><a href="howto_hierarchical.html#The_XPATH_expression_engine">The XPATH expression engine</a></li>
</ul>
<li><a href="howto_hierarchical.html#Builder_Configuration_Related_to_Hierarchical_Configurations">Builder Configuration Related to Hierarchical Configurations</a></li>
+ </ul>
+ <li><a href="howto_xml.html">XML Configurations</a></li>
+ <ul>
<li><a href="howto_xml.html#Validation_of_XML_configuration_files">Validation of XML configuration files</a></li>
</ul>
<li><a href="howto_reloading.html#Composite_Configuration_Details">Automatic Reloading of Configuration Sources</a></li>