Return-Path:
cite
element the comma is escaped, so that no splitting is
* performed.
The configuration API allows setting multiple values for a single attribute, + * e.g. something like the following is legal (assuming that the default + * expression engine is used): + *
+ * XMLConfiguration config = new XMLConfiguration(); + * config.addProperty("test.dir[@name]", "C:\\Temp\\"); + * config.addProperty("test.dir[@name]", "D:\\Data\\"); + *+ * + *
Because in XML such a constellation is not directly supported (an attribute
+ * can appear only once for a single element), the values are concatenated to a
+ * single value. If delimiter parsing is enabled (refer to the
+ * {@link #setDelimiterParsingDisabled(boolean)}
method), the
+ * current list delimiter character will be used as separator. Otherwise the
+ * pipe symbol ("|") will be used for this purpose. No matter which character is
+ * used as delimiter, it can always be escaped with a backslash. A backslash
+ * itself can also be escaped with another backslash. Consider the following
+ * example fragment from a configuration file:
+ *
+ * <directories names="C:\Temp\\|D:\Data\"/> + *+ * Here the backslash after Temp is escaped. This is necessary because it + * would escape the list delimiter (the pipe symbol assuming that list delimiter + * parsing is disabled) otherwise. So this attribute would have two values. + * + *
Note: You should ensure that the delimiter parsing disabled + * property is always consistent when you load and save a configuration file. + * Otherwise the values of properties can become corrupted.
+ * *XMLConfiguration
implements the {@link FileConfiguration}
* interface and thus provides full support for loading XML documents from
* different sources like files, URLs, or streams. A full description of these
@@ -102,7 +130,7 @@
* @since commons-configuration 1.0
*
* @author Jörg Schaible
- * @author Oliver Heger
+ * @author Oliver Heger
* @version $Revision$, $Date$
*/
public class XMLConfiguration extends AbstractHierarchicalFileConfiguration
@@ -115,6 +143,9 @@
/** Constant for the default root element name. */
private static final String DEFAULT_ROOT_NAME = "configuration";
+ /** Constant for the delimiter for multiple attribute values.*/
+ private static final char ATTR_VALUE_DELIMITER = '|';
+
/** The document from this configuration's data source. */
private Document document;
@@ -432,15 +463,10 @@
if (w3cNode instanceof Attr)
{
Attr attr = (Attr) w3cNode;
- Iterator it;
- if (isDelimiterParsingDisabled())
- {
- it = new SingletonIterator(attr.getValue());
- }
- else
- {
- it = PropertyConverter.split(attr.getValue(), getListDelimiter()).iterator();
- }
+ Iterator it = PropertyConverter.split(
+ attr.getValue(),
+ isDelimiterParsingDisabled() ? ATTR_VALUE_DELIMITER
+ : getListDelimiter()).iterator();
while (it.hasNext())
{
Node child = new XMLNode(attr.getName(),
@@ -570,7 +596,8 @@
document = newDocument;
}
- XMLBuilderVisitor builder = new XMLBuilderVisitor(document, getListDelimiter());
+ XMLBuilderVisitor builder = new XMLBuilderVisitor(document,
+ isDelimiterParsingDisabled() ? (char) 0 : getListDelimiter());
builder.processDocument(getRoot());
return document;
} /* try */
@@ -966,8 +993,12 @@
Element elem = document.createElement(newNode.getName());
if (newNode.getValue() != null)
{
- elem.appendChild(document.createTextNode(
- PropertyConverter.escapeDelimiters(newNode.getValue().toString(), listDelimiter)));
+ String txt = newNode.getValue().toString();
+ if (listDelimiter != 0)
+ {
+ txt = PropertyConverter.escapeDelimiters(txt, listDelimiter);
+ }
+ elem.appendChild(document.createTextNode(txt));
}
if (sibling2 == null)
{
@@ -992,7 +1023,7 @@
* @param node the affected node
* @param elem the element that is associated with this node
* @param name the name of the affected attribute
- * @param listDelimiter the delimiter vor attributes with multiple values
+ * @param listDelimiter the delimiter for attributes with multiple values
*/
private static void updateAttribute(Node node, Element elem, String name, char listDelimiter)
{
@@ -1000,6 +1031,7 @@
{
List attrs = node.getAttributes(name);
StringBuffer buf = new StringBuffer();
+ char delimiter = (listDelimiter != 0) ? listDelimiter : ATTR_VALUE_DELIMITER;
for (Iterator it = attrs.iterator(); it.hasNext();)
{
Node attr = (Node) it.next();
@@ -1007,10 +1039,10 @@
{
if (buf.length() > 0)
{
- buf.append(listDelimiter);
+ buf.append(delimiter);
}
buf.append(PropertyConverter.escapeDelimiters(attr
- .getValue().toString(), getDefaultListDelimiter()));
+ .getValue().toString(), delimiter));
}
attr.setReference(elem);
}
Modified: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestXMLConfiguration.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestXMLConfiguration.java?view=diff&rev=536326&r1=536325&r2=536326
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestXMLConfiguration.java (original)
+++ jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestXMLConfiguration.java Tue May 8 13:55:42 2007
@@ -1062,6 +1062,76 @@
}
/**
+ * Tests saving and loading a configuration when delimiter parsing is
+ * disabled.
+ */
+ public void testSaveDelimiterParsingDisabled()
+ throws ConfigurationException
+ {
+ checkSaveDelimiterParsingDisabled("list.delimiter.test");
+ }
+
+ /**
+ * Tests saving and loading a configuration when delimiter parsing is
+ * disabled and attributes are involved.
+ */
+ public void testSaveDelimiterParsingDisabledAttrs()
+ throws ConfigurationException
+ {
+ checkSaveDelimiterParsingDisabled("list.delimiter.test[@attr]");
+ }
+
+ /**
+ * Helper method for testing saving and loading a configuration when
+ * delimiter parsing is disabled.
+ *
+ * @param key the key to be checked
+ * @throws ConfigurationException if an error occurs
+ */
+ private void checkSaveDelimiterParsingDisabled(String key)
+ throws ConfigurationException
+ {
+ conf.clear();
+ conf.setDelimiterParsingDisabled(true);
+ conf.load();
+ conf.setProperty(key, "C:\\Temp\\,C:\\Data\\");
+ conf.addProperty(key, "a,b,c");
+ conf.save(testSaveConf);
+ XMLConfiguration checkConf = new XMLConfiguration();
+ checkConf.setDelimiterParsingDisabled(true);
+ checkConf.setFile(testSaveConf);
+ checkSavedConfig(checkConf);
+ }
+
+ /**
+ * Tests multiple attribute values in delimiter parsing disabled mode.
+ */
+ public void testDelimiterParsingDisabledMultiAttrValues() throws ConfigurationException
+ {
+ conf.clear();
+ conf.setDelimiterParsingDisabled(true);
+ conf.load();
+ List expr = conf.getList("expressions[@value]");
+ assertEquals("Wrong list size", 2, expr.size());
+ assertEquals("Wrong element 1", "a || (b && c)", expr.get(0));
+ assertEquals("Wrong element 2", "!d", expr.get(1));
+ }
+
+ /**
+ * Tests using multiple attribute values, which are partly escaped when
+ * delimiter parsing is not disabled.
+ */
+ public void testMultipleAttrValuesEscaped() throws ConfigurationException
+ {
+ conf.addProperty("test.dir[@name]", "C:\\Temp\\");
+ conf.addProperty("test.dir[@name]", "C:\\Data\\");
+ conf.save(testSaveConf);
+ XMLConfiguration checkConf = new XMLConfiguration();
+ checkConf.setFile(testSaveConf);
+ checkSavedConfig(checkConf);
+ }
+
+ /**
* Prepares a configuration object for testing a reload operation.
*
* @return the initialized configuration
Modified: jakarta/commons/proper/configuration/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/xdocs/changes.xml?view=diff&rev=536326&r1=536325&r2=536326
==============================================================================
--- jakarta/commons/proper/configuration/trunk/xdocs/changes.xml (original)
+++ jakarta/commons/proper/configuration/trunk/xdocs/changes.xml Tue May 8 13:55:42 2007
@@ -23,6 +23,12 @@