XML Configuration File Processor
Introduction
It is currently common to build a number of releases from a single code base. For example, a development release, a QA release, a production release and perhaps customer-specific releases. However, these releases seem to differ mostly in the contents of their XML configuration files, and then only very little. Maintaining all these slightly different configuration files is a real nuisance.
XConf was created to simplify this maintenance. Its fundamental premise is that a single development-release (or production-release) configuration file is created and maintained, and is processed by XConf at either build or deployment time into an appropriate release by applying one or more XML-based scripts. Each script contains only the differences required to create the appropriate release, thus removing the need for the mass duplication of configuration files.
This is not really a new solution, since XSLT has been used in the past to do this quite successfully, but XPath can get a little arcane, and maintaining transformation scripts using XSLT can become really complex very quickly. XConf uses a very simple and compact method of specifying elements that need to be processed, and provides some very useful constructs to make transformations painless.
UPDATE: XConf is now able to process properties configuration files in addition to XML files. Check out usage and requirements and properties file processing below for more information.
Project Links
Usage
XConf can be invoked from the command line or shell scripts using:java -jar xconf-standalone.jar [arguments] -config <file> (Required) full path to configuration file -in <file> (Required) full path to input file to be processed -out <file> (Required) full path to processed output file -tokens <file> (Optional) full path to properties file containing replacement tokens -properties (Optional) process config, in & out as properties files -validate (Optional) validate input XML file
- XML Validation
- By default, XConf does not validate the input XML file, and if a Xerces SAX parser is present in the classpath, XConf completely ignores any DTDs. All it really requires is a well-formed XML file. You can force XConf to validate any input XML files it processes by adding the optional -validate argument to the invocation command line.
- XML File Processing
- By default, XConf assumes that both the configuration and input files are XML. You can direct it to process them as properties files by adding the optional -properties to the invocation command line. In that case, the configuration file should be a properties file in the format described by properties file processing, and the input file should also be a valid properties file.
<target name="create-production-config"> <taskdef name="xconf" classname="net.sourceforge.xconf.AntTask"> <classpath> <pathelement location="lib/xconf-standalone.jar"/> </classpath> </taskdef> <xconf config="etc/production.xml" input="war/WEB-INF/web.xml" output="${dist.dir}/web.xml"> <token name="sessionTimeout" value="30" /> </xconf> </target>
xconf
Attribute | Description | Required |
---|---|---|
config | Absolute or relative path to a processing script file | Yes |
input | Absolute or relative path to a file to process | Yes |
output | Absolute or relative path to output the processed file | Yes |
validate | Validate the input XML file against its declared DTD. Default is "false". | No |
properties | Treat the config, input and output files as properties and not XML. Default is "false". | No |
tokens | Use replacement tokens from the given properties file. | No |
token
Each xconf task can contain token
elements that represent replacement tokens for processing directives.
These are usually supplied to the command line instance from a properties file referenced by the -tokens
optional flag. These token
elements will replace any conflicting values provided via the tokens attribute.
Attribute | Description | Required |
---|---|---|
name | ${token} to be replaced | Yes |
value | replacement value | Yes |
XML Script Example
During development, a web application has a 30 minute timeout, but for production the timeout should be set to 5 minutes.<web-app> ... <session-config> <session-timeout>30</session-timeout> </session-config> ... </web-app>The following script can be applied using XConf to change the session timeout during a production build.
<?xml version="1.0"?> <xconf> <setText path="web-app/session-config/session-timeout"> <text>5</text> </setText> </xconf>Resulting in the following production release web.xml.
<web-app> ... <session-config> <session-timeout>5</session-timeout> </session-config> ... </web-app>
Processing Actions
NOTE: All processing actions require a path attribute to define the XML element(s) in the input file that will be altered/processed. See the Path Syntax section below for a description of the contents of this attribute.- 1. setText
-
- sets the text content of an XML element
- uses a <text> child element to define the new text content
- the text element's content can contain replacement tokens.
- Example: Set the session timeout of a web application to 20 minutes:<setText path="web-app/session-config/session-timeout"> <text>20</text> </setText>
- As of release 1.9.6 the text child element is optional, so you could rewrite the above as:<setText path="web-app/session-config/session-timeout">20</setText>
- 2. removeText
-
- removes the text content of an XML element
- Example: Remove the title from an XHTML document:<removeText path="html/head/title"/>
- 3. setAttribute
-
- sets and adds attributes to an XML element
- requires <attribute> child elements to provide the name and value for each new attribute
- attribute name and value can contain replacement tokens.
- Example: Set the path of all tiles definitions:<setAttribute path="tiles-definitions/definition"> <attribute name="path" value="/WEB-INF/vm/layout/layout.vm"/> </setAttribute>
- 4. removeAttribute
-
- removes attributes from an XML element
- requires <attribute> child elements to provide the name of the attributes to be removed
- Example: Remove the singleton attribute from all spring beans:<removeAttribute path="beans/bean"> <attribute name="singleton"/> </removeAttribute>
- 5. addElement
-
- adds new child element(s) to an existing XML element
- requires 1 or more child elements as prototypes for the new element or elements
- Example: Add a new put element to all tiles definitions:<addElement path="tiles-definitions/definition"> <put name="header" value="/WEB-INF/vm/layout/header.vm"/> </addElement>
- 6. removeElement
-
- removes an XML element from the document
- Example: Remove the session timeout setting from a web application:<removeElement path="web-app/session-config/session-timeout"/>
- 7. replaceElement
-
- replaces an existing XML element
- requires 1 or more child elements as prototypes for the replacement element or elements
- Example: Redefine an existing tiles root layout:<replaceElement path="tiles-definitions/definition[+a|name|rootLayout]"> <definition name="rootLayout" path="/WEB-INF/vm/layout/layout.vm"> <put name="title" value=""/> <put name="header" value="/WEB-INF/vm/layout/header.vm"/> <put name="menu" value="/WEB-INF/vm/layout/menu.vm"/> <put name="body" value=""/> <put name="footer" value="/WEB-INF/vm/layout/footer.vm"/> </definition> </replaceElement>
Path Syntax
All these nice processing actions would be pretty pointless without a compact way of describing the elements that need to be processed. If this syntax looks similar to XPath, it is not an accident.
Each element in an XML document tree is defined by a node in the path string.path := node/node/node node := element OR element[constraint] OR .. (parent element) element := name of XML element OR * (all elements) constraint := [+-]cType|cName(|cValue) [+-] := + (include), - (exclude) cType := a (attribute), t (text), c (child) cName := name of attribute for (a), normalized text for (t), name of child element for (c) cValue := optional, for (a) it is the value of named attribute, and for (c) it is the normalized text content of the child elementSo, for example if we want to remove the singleton attribute only from spring beans that have an attribute named "id" with a value of "dataSource", we would create a removeAttribute action with:
<removeAttribute path="beans/bean[+a|id|dataSource]"> <attribute name="singleton"/> </removeAttribute>In a more complex example, if we want to change the value of the obfuscatedParams initialisation parameter in a web application filter named RequestTraceFilter, we would create a setText action with:
<setText path="web-app/filter/filter-name[+t|RequestTraceFilter]/../init-param/param-name[+t|obfuscatedParams]/../param-value"> <text>password,repeatPassword</text> </setText>Try doing this with XSLT and see how many lines it takes :-)
XML Script Constants
These are optional node
and path
elements that describe replacement tokens which can be
used in the path
attributes of processing actions.
<?xml version="1.0"?> <xconf> <setText path="web-app/session-config/session-timeout"> <text>20</text> </setText> <removeElement path="web-app/servlet/servlet-name[+t|velocity]/.." /> <setText path="web-app/filter/filter-name[+t|RequestTraceFilter]/../init-param/param-name[+t|obfuscatedParams]/../param-value"> <text>password,repeatPassword</text> </setText> </xconf>Same script with constants:
<?xml version="1.0"?> <xconf> <node name="requestTraceFilter" value="filter-name[+t|RequestTraceFilter]"/> <node name="obfuParamsName" value="param-name[+t|obfuscatedParams]"/> <path name="obfuParamsValue" value="init-param/${obfuParamsName}/../param-value"/> <setText path="web-app/session-config/session-timeout"> <text>20</text> </setText> <removeElement path="web-app/servlet/servlet-name[+t|velocity]/.." /> <setText path="web-app/filter/${requestTraceFilter}/../${obfuParamsValue}"> <text>password,repeatPassword</text> </setText> </xconf>Constant definitions:
- 1. node
-
- can be used to define a single path node for reuse in multiple path definitions.
- can also be used to define nodes that contain '/' characters, which will otherwise lead to path attribute parsing errors. For example:element[+a|url|http://localhost.com]
- it is referenced in action path attributes by enclosing its name in '${' and '}' characters.
- Example: redefine a Spring DataSource's jndi name:<node name="jndiRef" value="value[+t|java:comp/env/jdbc/catalogue]"/> <setText path="beans/bean[+a|id|dataSource]/property/${jndiRef}"> <text>java:comp/env/jdbc/catalogue2</text> </setText>
- 2. path
-
- can be used to define a complete or partial path for reuse in multiple action path attributes.
- may be composed of previously declared path and node constant references.
- it is referenced in action path attributes by enclosing its name in '${' and '}' characters.
- Example: perform multiple processing actions on a web-app filter definition:<path name="requestTraceFilter" value="web-app/filter/filter-name[+t|RequestTraceFilter]/.."/> <path name="obfuscatedParams" value="${requestTraceFilter}/init-param/param-name[+t|obfuscatedParams]/.."/> <removeElement path="${requestTraceFilter}/init-param"/> <setText path="${obfuscatedParams}/param-value"> <text>password,repeatPassword</text> </setText>
Properties File Processing
Processing of properties files is currently done in a very simple manner. At the start of processing, 2 properties files are read by XConf. The first is a config file describing the processing actions to take, and the second is an input file to be processed. The config file is then used to process the input file, creating an output properties file that contains the results of the processing.-
Any property in the config file with a value of "
XCONFDELETE
", if present in the input file, will not appear in the output file. -
All other properties in the config file will simply be set as properties in
the output file using values from the config file, possibly overwriting properties
that exist in the input file. The properties from the config file can contain replacement tokens
(ie.
${key}
) to be replaced with values from either the configproperties file when run as a standalone application, or from properties in the ant project when run as an ant task. - All input file properties that are not overwritten or deleted by the config file, are simply copied into the output file.
java.util.Properties
API does not guarantee the
order of key/value pairs.
Copyright © 2007-2013 Thomas Czarniecki. All Rights Reserved.