I prepared a patch to remove the dom4j configurations as discussed earlier, it does the following:
- remove XMLConfiguration
- rename DOMConfiguration into XMLConfiguration
- remove DOM4JConfiguration
- rename HierarchicalDOMConfiguration into HierarchicalXMLConfiguration
- remove HierarchicalDOM4JConfiguration
- change ConfigurationFactory to handle the 'xml' and 'hierarchicalXml' elements instead of 'dom4j' and 'hierarchicalDom4j'
- documentation update
- unit test update (classes and test files)


It doesn't remove completely the dependency on dom4j, ConfigurationXMLDocument still use it to convert a configuration into a dom4j document and I don't plan to remove this feature. However two distinct classes to convert a configuration into a DOM document and a dom4j would be better imho. I also consider moving the xml related classes (*XMLReader & *XMLDocument) to an xml sub package, I believe theses classes are not central to the [configuration] goal and deserve a sub package.

If nobody objects I'll apply the patch tomorrow.

Emmanuel Bourg

Index: conf/digesterRules.xml
===================================================================
RCS file: /home/cvs/jakarta-commons/configuration/conf/digesterRules.xml,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 digesterRules.xml
--- conf/digesterRules.xml      23 Dec 2003 15:09:05 -0000      1.1.1.1
+++ conf/digesterRules.xml      8 Jul 2004 11:02:47 -0000
@@ -1,22 +1,26 @@
 <?xml version="1.0"?>
 <!DOCTYPE digester-rules PUBLIC "-//Jakarta Apache //DTD digester-rules XML V1.0//EN" 
"http://jakarta.apache.org/commons/digester/dtds/digester-rules.dtd";>
+
 <digester-rules>
-  <pattern value="configuration/properties">
-    <object-create-rule 
classname="org.apache.commons.configuration.PropertiesConfiguration"/>
-    <set-properties-rule/>
-    <set-next-rule methodname="addConfiguration" 
paramtype="org.apache.commons.configuration.Configuration"/>
-    <call-method-rule methodname="load"/>
-  </pattern>
-  <pattern value="configuration/dom4j">
-    <object-create-rule 
classname="org.apache.commons.configuration.DOM4JConfiguration"/>
-    <set-properties-rule/>
-    <set-next-rule methodname="addConfiguration" 
paramtype="org.apache.commons.configuration.Configuration"/>
-    <call-method-rule methodname="load"/>
-  </pattern>  
-  <pattern value="configuration/jndi">
-    <object-create-rule 
classname="org.apache.commons.configuration.JNDIConfiguration"/>
-    <set-properties-rule/>
-    <set-next-rule methodname="addConfiguration" 
paramtype="org.apache.commons.configuration.Configuration"/>
-    
-  </pattern>    
+
+    <pattern value="configuration/properties">
+        <object-create-rule 
classname="org.apache.commons.configuration.PropertiesConfiguration"/>
+        <set-properties-rule/>
+        <set-next-rule methodname="addConfiguration" 
paramtype="org.apache.commons.configuration.Configuration"/>
+        <call-method-rule methodname="load"/>
+    </pattern>
+
+    <pattern value="configuration/xml">
+        <object-create-rule 
classname="org.apache.commons.configuration.XMLConfiguration"/>
+        <set-properties-rule/>
+        <set-next-rule methodname="addConfiguration" 
paramtype="org.apache.commons.configuration.Configuration"/>
+        <call-method-rule methodname="load"/>
+    </pattern>
+
+    <pattern value="configuration/jndi">
+        <object-create-rule 
classname="org.apache.commons.configuration.JNDIConfiguration"/>
+        <set-properties-rule/>
+        <set-next-rule methodname="addConfiguration" 
paramtype="org.apache.commons.configuration.Configuration"/>
+    </pattern>
+
 </digester-rules>
Index: conf/testConfigurationXMLDocument.xml
===================================================================
RCS file: 
/home/cvs/jakarta-commons/configuration/conf/testConfigurationXMLDocument.xml,v
retrieving revision 1.3
diff -u -r1.3 testConfigurationXMLDocument.xml
--- conf/testConfigurationXMLDocument.xml       8 Mar 2004 23:27:09 -0000       1.3
+++ conf/testConfigurationXMLDocument.xml       8 Jul 2004 11:02:47 -0000
@@ -3,14 +3,8 @@
 
 <configuration>
   <additional>
-    <hierarchicalDom4j fileName="testHierarchicalDOM4JConfiguration.xml" 
at="database"/>
-    <hierarchicalDom4j fileName="testDigesterConfigurationInclude1.xml" 
at="database.tables"/>
-    <hierarchicalDom4j fileName="testDigesterCreateObject.xml" at="database"/>
+    <hierarchicalXml fileName="testHierarchicalXMLConfiguration.xml" at="database"/>
+    <hierarchicalXml fileName="testDigesterConfigurationInclude1.xml" 
at="database.tables"/>
+    <hierarchicalXml fileName="testDigesterCreateObject.xml" at="database"/>
   </additional>
 </configuration>
-
-  
-  
-
-
-
Index: conf/testDigesterBadXML.xml
===================================================================
RCS file: /home/cvs/jakarta-commons/configuration/conf/testDigesterBadXML.xml,v
retrieving revision 1.1
diff -u -r1.1 testDigesterBadXML.xml
--- conf/testDigesterBadXML.xml 23 Jan 2004 11:52:36 -0000      1.1
+++ conf/testDigesterBadXML.xml 8 Jul 2004 11:02:47 -0000
@@ -5,7 +5,7 @@
 
 <configuration>
   <additional>
-    <dom4j 
className="org.apache.commons.configuration.HierarchicalDOM4JConfiguration" 
fileName="testHierarchicalDOM4JConfiguration.xml"/>
+    <xml className="org.apache.commons.configuration.HierarchicalXMLConfiguration" 
fileName="testHierarchicalXMLConfiguration.xml"/>
    
 </configuration>
 
Index: conf/testDigesterConfiguration.xml
===================================================================
RCS file: /home/cvs/jakarta-commons/configuration/conf/testDigesterConfiguration.xml,v
retrieving revision 1.2
diff -u -r1.2 testDigesterConfiguration.xml
--- conf/testDigesterConfiguration.xml  8 Mar 2004 23:21:30 -0000       1.2
+++ conf/testDigesterConfiguration.xml  8 Jul 2004 11:02:47 -0000
@@ -2,11 +2,5 @@
 
 <configuration>
   <properties fileName="conf/test.properties"/>
-  <dom4j fileName="conf/test.xml"/>
+  <xml fileName="conf/test.xml"/>
 </configuration>
-
-  
-  
-
-
-
Index: conf/testDigesterConfiguration2.xml
===================================================================
RCS file: /home/cvs/jakarta-commons/configuration/conf/testDigesterConfiguration2.xml,v
retrieving revision 1.3
diff -u -r1.3 testDigesterConfiguration2.xml
--- conf/testDigesterConfiguration2.xml 8 Mar 2004 23:21:30 -0000       1.3
+++ conf/testDigesterConfiguration2.xml 8 Jul 2004 11:02:47 -0000
@@ -4,8 +4,8 @@
 
 <configuration>
   <additional>
-    <hierarchicalDom4j fileName="testHierarchicalDOM4JConfiguration.xml"/>
-    <hierarchicalDom4j fileName="testDigesterConfigurationInclude1.xml" at="tables"/>
+    <hierarchicalXml fileName="testHierarchicalXMLConfiguration.xml"/>
+    <hierarchicalXml fileName="testDigesterConfigurationInclude1.xml" at="tables"/>
     <properties fileName="testDigesterConfigurationInclude2.properties" at="mail"/>
   </additional>
 
@@ -13,9 +13,3 @@
     <properties fileName="testDigesterConfigurationOverwrite.properties"/>
   </override>
 </configuration>
-
-  
-  
-
-
-
Index: conf/testDigesterConfiguration3.xml
===================================================================
RCS file: /home/cvs/jakarta-commons/configuration/conf/testDigesterConfiguration3.xml,v
retrieving revision 1.1
diff -u -r1.1 testDigesterConfiguration3.xml
--- conf/testDigesterConfiguration3.xml 14 Feb 2004 20:06:23 -0000      1.1
+++ conf/testDigesterConfiguration3.xml 8 Jul 2004 11:02:47 -0000
@@ -3,15 +3,9 @@
 
 <configuration>
   <additional>
-    <dom4j fileName="test.xml"/>
-    <hierarchicalDom4j fileName="testDigesterConfigurationInclude1.xml" at="tables"/>
+    <xml fileName="test.xml"/>
+    <hierarchicalXml fileName="testDigesterConfigurationInclude1.xml" at="tables"/>
     <properties fileName="testDigesterConfigurationInclude2.properties" at="mail"/>
     <jndi prefix=""/>
   </additional>
 </configuration>
-
-  
-
-
-
-
Index: conf/testDigesterConfigurationNamespaceAware.xml
===================================================================
RCS file: 
/home/cvs/jakarta-commons/configuration/conf/testDigesterConfigurationNamespaceAware.xml,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 testDigesterConfigurationNamespaceAware.xml
--- conf/testDigesterConfigurationNamespaceAware.xml    23 Dec 2003 15:09:05 -0000     
 1.1.1.1
+++ conf/testDigesterConfigurationNamespaceAware.xml    8 Jul 2004 11:02:47 -0000
@@ -1,16 +1,7 @@
 <?xml version="1.0" encoding="ISO-8859-1" ?>
 
-
-
 <configuration xmlns:foo="namespace-one"
                xmlns:bar="namespace-two">
   <foo:properties 
className="org.apache.commons.configuration.PropertiesConfiguration" 
fileName="conf/test.properties"/>
-  <bar:dom4j className="org.apache.commons.configuration.DOM4JConfiguration" 
fileName="conf/test.xml"/>
+  <bar:dom className="org.apache.commons.configuration.XMLConfiguration" 
fileName="conf/test.xml"/>
 </configuration>
-
-
-  
-  
-
-
-
Index: conf/testDigesterConfigurationReverseOrder.xml
===================================================================
RCS file: 
/home/cvs/jakarta-commons/configuration/conf/testDigesterConfigurationReverseOrder.xml,v
retrieving revision 1.2
diff -u -r1.2 testDigesterConfigurationReverseOrder.xml
--- conf/testDigesterConfigurationReverseOrder.xml      8 Mar 2004 23:21:30 -0000      
 1.2
+++ conf/testDigesterConfigurationReverseOrder.xml      8 Jul 2004 11:02:47 -0000
@@ -1,13 +1,6 @@
 <?xml version="1.0" encoding="ISO-8859-1" ?>
 
 <configuration>
-  <dom4j fileName="conf/test.xml"/>
+  <xml fileName="conf/test.xml"/>
   <properties fileName="conf/test.properties"/>
-  
 </configuration>
-
-  
-  
-
-
-
Index: conf/testDigesterConfigurationWJNDI.xml
===================================================================
RCS file: 
/home/cvs/jakarta-commons/configuration/conf/testDigesterConfigurationWJNDI.xml,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 testDigesterConfigurationWJNDI.xml
--- conf/testDigesterConfigurationWJNDI.xml     23 Dec 2003 15:09:05 -0000      1.1.1.1
+++ conf/testDigesterConfigurationWJNDI.xml     8 Jul 2004 11:02:47 -0000
@@ -3,13 +3,5 @@
 <configuration>
   <jndi className="org.apache.commons.configuration.JNDIConfiguration" 
prefix="java:comp/env"/>
   <properties className="org.apache.commons.configuration.PropertiesConfiguration" 
fileName="conf/test.properties"/>
-  <dom4j className="org.apache.commons.configuration.DOM4JConfiguration" 
fileName="conf/test.xml"/>
-  
-  
+  <dom className="org.apache.commons.configuration.XMLConfiguration" 
fileName="conf/test.xml"/>
 </configuration>
-
-  
-  
-
-
-
Index: src/java/org/apache/commons/configuration/ConfigurationFactory.java
===================================================================
RCS file: 
/home/cvs/jakarta-commons/configuration/src/java/org/apache/commons/configuration/ConfigurationFactory.java,v
retrieving revision 1.14
diff -u -r1.14 ConfigurationFactory.java
--- src/java/org/apache/commons/configuration/ConfigurationFactory.java 5 Jul 2004 
09:54:17 -0000       1.14
+++ src/java/org/apache/commons/configuration/ConfigurationFactory.java 8 Jul 2004 
11:02:47 -0000
@@ -278,18 +278,21 @@
             new BasePathConfigurationFactory(PropertiesConfiguration.class),
             METH_LOAD,
             additional);
+
         setupDigesterInstance(
             digester,
-            matchString + "dom4j",
-            new BasePathConfigurationFactory(DOM4JConfiguration.class),
+            matchString + "xml",
+            new BasePathConfigurationFactory(XMLConfiguration.class),
             METH_LOAD,
             additional);
+
         setupDigesterInstance(
             digester,
-            matchString + "hierarchicalDom4j",
-            new BasePathConfigurationFactory(HierarchicalDOM4JConfiguration.class),
+            matchString + "hierarchicalXml",
+            new BasePathConfigurationFactory(HierarchicalXMLConfiguration.class),
             METH_LOAD,
             additional);
+
         setupDigesterInstance(
             digester,
             matchString + "jndi",
@@ -310,11 +313,11 @@
      * added
      */
     protected void setupDigesterInstance(
-        Digester digester,
-        String matchString,
-        ObjectCreationFactory factory,
-        String method,
-        boolean additional)
+            Digester digester,
+            String matchString,
+            ObjectCreationFactory factory,
+            String method,
+            boolean additional)
     {
         if (additional)
         {
@@ -486,9 +489,8 @@
     /**
      * A tiny inner class that allows the Configuration Factory to
      * let the digester construct JNDIPathConfiguration objects.
-     *
      */
-    public class JNDIConfigurationFactory extends DigesterConfigurationFactory
+    private class JNDIConfigurationFactory extends DigesterConfigurationFactory
     {
         /**
          * C'tor
Index: src/java/org/apache/commons/configuration/ConfigurationUtils.java
===================================================================
RCS file: 
/home/cvs/jakarta-commons/configuration/src/java/org/apache/commons/configuration/ConfigurationUtils.java,v
retrieving revision 1.4
diff -u -r1.4 ConfigurationUtils.java
--- src/java/org/apache/commons/configuration/ConfigurationUtils.java   23 Jun 2004 
11:15:45 -0000      1.4
+++ src/java/org/apache/commons/configuration/ConfigurationUtils.java   8 Jul 2004 
11:02:48 -0000
@@ -151,7 +151,7 @@
      */
     static File constructFile(String basePath, String fileName)
     {
-        // code from DOM4JConfiguration
+        // code from XMLConfiguration
         File file = null;
         if (StringUtils.isEmpty(basePath))
         {
Index: src/java/org/apache/commons/configuration/XMLConfiguration.java
===================================================================
RCS file: 
/home/cvs/jakarta-commons/configuration/src/java/org/apache/commons/configuration/XMLConfiguration.java,v
retrieving revision 1.3
diff -u -r1.3 XMLConfiguration.java
--- src/java/org/apache/commons/configuration/XMLConfiguration.java     24 Jun 2004 
12:35:15 -0000      1.3
+++ src/java/org/apache/commons/configuration/XMLConfiguration.java     8 Jul 2004 
11:02:48 -0000
@@ -16,14 +16,473 @@
 
 package org.apache.commons.configuration;
 
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.net.URL;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.FactoryConfigurationError;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.commons.lang.StringUtils;
+import org.w3c.dom.Attr;
+import org.w3c.dom.CharacterData;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
 /**
- * Base class for reading an XML configuration file.
+ * Reads a XML configuration file.
  *
- * @since 0.8.1
+ * To retrieve the value of an attribute of an element, use
+ * <code>[EMAIL PROTECTED]</code>.  The '@' symbol was chosen for
+ * consistency with XPath.
  *
+ * Setting property values will <b>NOT</b> automatically persist
+ * changes to disk, unless <code>autoSave=true</code>.
+ *
+ * @since commons-configuration 1.0
+ *
+ * @author Jörg Schaible
+ * @author <a href="mailto:[EMAIL PROTECTED]">Kelvin Tan</a>
  * @author <a href="mailto:[EMAIL PROTECTED]">Daniel Rall</a>
- * @version $Revision: 1.3 $, $Date: 2004/06/24 12:35:15 $
+ * @version $Revision: 1.5 $, $Date: 2004/06/21 16:47:24 $
  */
-public abstract class XMLConfiguration extends BasePathConfiguration
+public class XMLConfiguration extends BasePathConfiguration
 {
+    // For conformance with xpath
+    private static final char ATTRIB_MARKER = '@';
+    private static final String ATTRIB_START_MARKER = "[" + ATTRIB_MARKER;
+
+    /**
+     * For consistency with properties files.  Access nodes via an
+     * "A.B.C" notation.
+     */
+    private static final String NODE_DELIMITER = ".";
+
+    /**
+     * A handle to our data source.
+     */
+    private String fileName;
+
+    /**
+     * The XML document from our data source.
+     */
+    private Document document;
+
+    /**
+     * If true, modifications are immediately persisted.
+     */
+    private boolean autoSave = false;
+
+    /**
+     * Empty construtor.  You must provide a file/fileName
+     * and call the load method
+     *
+     */
+    public XMLConfiguration()
+    {
+    }
+
+    /**
+     * Attempts to load the XML file as a resource from the
+     * classpath. The XML file must be located somewhere in the
+     * classpath.
+     *
+     * @param resource Name of the resource
+     * @throws ConfigurationException If error reading data source.
+     */
+    public XMLConfiguration(String resource) throws ConfigurationException
+    {
+        setFile(resourceURLToFile(resource));
+        load();
+    }
+
+    /**
+     * Attempts to load the XML file.
+     *
+     * @param file File object representing the XML file.
+     * @throws ConfigurationException If error reading data source.
+     */
+    public XMLConfiguration(File file) throws ConfigurationException
+    {
+        setFile(file);
+        load();
+    }
+
+    public void load() throws ConfigurationException
+    {
+        File file = null;
+        try
+        {
+            URL url = ConfigurationUtils.getURL(getBasePath(), getFileName());
+            file = new File(url.getFile());
+            DocumentBuilder builder = 
DocumentBuilderFactory.newInstance().newDocumentBuilder();
+            document = builder.parse(file);
+        }
+        catch (IOException de)
+        {
+            throw new ConfigurationException("Could not load from " + 
file.getAbsolutePath());
+        }
+        catch (ParserConfigurationException ex)
+        {
+            throw new ConfigurationException("Could not configure parser");
+               }
+        catch (FactoryConfigurationError ex)
+        {
+            throw new ConfigurationException("Could not create parser");
+        }
+        catch (SAXException ex)
+        {
+            throw new ConfigurationException("Error parsing file " + 
file.getAbsolutePath());
+               }
+
+        initProperties(document.getDocumentElement(), new StringBuffer());
+    }
+
+    private static File resourceURLToFile(String resource)
+    {
+        URL confURL = XMLConfiguration.class.getClassLoader().getResource(resource);
+        if (confURL == null)
+        {
+            confURL = ClassLoader.getSystemResource(resource);
+        }
+        return new File(confURL.getFile());
+    }
+
+    /**
+     * Loads and initializes from the XML file.
+     *
+     * @param element The element to start processing from.  Callers
+     *                should supply the root element of the document.
+     * @param hierarchy
+     */
+    private void initProperties(Element element, StringBuffer hierarchy)
+    {
+        StringBuffer buffer = new StringBuffer();
+        NodeList list = element.getChildNodes();
+        for (int i = 0; i < list.getLength(); i++)
+        {
+            Node node = list.item(i);
+            if (node instanceof Element)
+            {
+                StringBuffer subhierarchy = new StringBuffer(hierarchy.toString());
+                Element child = (Element) node;
+                subhierarchy.append(child.getTagName());
+                processAttributes(subhierarchy.toString(), child);
+                initProperties(child,
+                        new StringBuffer(subhierarchy.toString()).append('.'));
+            }
+            else if (node instanceof CharacterData)
+            {
+                CharacterData data = (CharacterData)node;
+                buffer.append(data.getData());
+            }
+        }
+        String text = buffer.toString().trim();
+        if (text.length() > 0 && hierarchy.length() > 0)
+        {
+            super.addProperty(
+                    hierarchy.substring(0, hierarchy.length()-1), text);
+        }
+    }
+
+    /**
+     * Helper method for constructing properties for the attributes of the
+     * given XML element.
+     *
+     * @param hierarchy the actual hierarchy
+     * @param element the actual XML element
+     */
+    private void processAttributes(String hierarchy, Element element)
+    {
+        // Add attributes as x.y{ATTRIB_START_MARKER}att{ATTRIB_END_MARKER}
+        NamedNodeMap attributes = element.getAttributes();
+        for (int i = 0; i < attributes.getLength(); ++i)
+        {
+            Node node = attributes.item(i);
+            if (node instanceof Attr)
+            {
+                Attr attr = (Attr) node;
+                String attrName = hierarchy + '[' + ATTRIB_MARKER + attr.getName() + 
']';
+                super.addProperty(attrName, attr.getValue());
+            }
+        }
+    }
+
+    /**
+     * Calls super method, and also ensures the underlying [EMAIL PROTECTED]
+     * Document} is modified so changes are persisted when saved.
+     *
+     * @param name
+     * @param value
+     */
+    public void addProperty(String name, Object value)
+    {
+        super.addProperty(name, value);
+        setXmlProperty(name, value);
+        possiblySave();
+    }
+
+    /**
+     * Calls super method, and also ensures the underlying [EMAIL PROTECTED]
+     * Document} is modified so changes are persisted when saved.
+     *
+     * @param name
+     * @param value
+     */
+    public void setProperty(String name, Object value)
+    {
+        super.setProperty(name, value);
+        setXmlProperty(name, value);
+        possiblySave();
+    }
+
+    /**
+     * Sets the property value in our document tree, auto-saving if
+     * appropriate.
+     *
+     * @param name The name of the element to set a value for.
+     * @param value The value to set.
+     */
+    private void setXmlProperty(String name, Object value)
+    {
+        String[] nodes = StringUtils.split(name, NODE_DELIMITER);
+        String attName = null;
+        Element element = document.getDocumentElement();
+        for (int i = 0; i < nodes.length; i++)
+        {
+            String eName = nodes[i];
+            int index = eName.indexOf(ATTRIB_START_MARKER);
+            if (index > -1)
+            {
+                attName = eName.substring(index + ATTRIB_START_MARKER.length(), 
eName.length() - 1);
+                eName = eName.substring(0, index);
+            }
+
+            Element child = null;
+            NodeList list = element.getChildNodes();
+            for (int j = 0; j < list.getLength(); j++)
+            {
+                Node node = list.item(j);
+                if (node instanceof Element)
+                {
+                    child = (Element) node;
+                    if (eName.equals(child.getTagName()))
+                    {
+                        break;
+                    }
+                    child = null;
+                }
+            }
+            // If we don't find this part of the property in the XML hierarchy
+            // we add it as a new node
+            if (child == null && attName == null)
+            {
+                child = document.createElement(eName);
+                element.appendChild(child);
+            }
+            element = child;
+        }
+
+        if (attName == null)
+        {
+            CharacterData data = document.createTextNode((String) value);
+            element.appendChild(data);
+        }
+        else
+        {
+            element.setAttribute(attName, (String) value);
+        }
+    }
+
+    /**
+     * Calls super method, and also ensures the underlying [EMAIL PROTECTED] 
Document} is
+     * modified so changes are persisted when saved.
+     *
+     * @param name The name of the property to clear.
+     */
+    public void clearProperty(String name)
+    {
+        super.clearProperty(name);
+        clearXmlProperty(name);
+        possiblySave();
+    }
+
+    private void clearXmlProperty(String name)
+    {
+        String[] nodes = StringUtils.split(name, NODE_DELIMITER);
+        String attName = null;
+        Element element = null;
+        Element child = document.getDocumentElement();
+        for (int i = 0; i < nodes.length; i++)
+        {
+            element = child;
+            String eName = nodes[i];
+            int index = eName.indexOf(ATTRIB_START_MARKER);
+            if (index > -1)
+            {
+                attName = eName.substring(index + ATTRIB_START_MARKER.length(), 
eName.length() - 1);
+                eName = eName.substring(0, index);
+            }
+
+            NodeList list = element.getChildNodes();
+            for (int j = 0; j < list.getLength(); j++) {
+                Node node = list.item(j);
+                if (node instanceof Element)
+                {
+                    child = (Element) node;
+                    if (eName.equals(child.getTagName()))
+                    {
+                        break;
+                    }
+                    child = null;
+                }
+            }
+            if (child == null)
+            {
+                return;
+            }
+        }
+
+        if (attName == null)
+        {
+            element.removeChild(child);
+        }
+        else
+        {
+            child.removeAttribute(attName);
+        }
+    }
+
+    /**
+     * Save the configuration if the automatic persistence is enabled.
+     */
+    private void possiblySave()
+    {
+        if (autoSave)
+        {
+            try
+            {
+                save();
+            }
+            catch (ConfigurationException ce)
+            {
+                throw new ConfigurationRuntimeException("Failed to auto-save", ce);
+            }
+        }
+    }
+
+    /**
+     * If true, changes are automatically persisted.
+     *
+     * @param autoSave
+     */
+    public void setAutoSave(boolean autoSave)
+    {
+        this.autoSave = autoSave;
+    }
+
+    public synchronized void save() throws ConfigurationException
+    {
+        FileWriter writer = null;
+        try
+        {
+            writer = new FileWriter(getFile());
+            writer.write(toString());
+        }
+        catch (IOException ioe){
+               throw new ConfigurationException("Could not save to " + getFile());
+        }
+        finally
+        {
+               try
+            {
+                if (writer != null)
+                {
+                    writer.close();
+                }
+               }
+               catch (IOException ioe)
+            {
+                       throw new ConfigurationException(ioe);
+               }
+        }
+    }
+
+    /**
+     * Returns the file.
+     *
+     * @return File
+     */
+    public File getFile()
+    {
+        return ConfigurationUtils.constructFile(getBasePath(), getFileName());
+    }
+
+    /**
+     * Sets the file.
+     *
+     * @param file The file to set
+     */
+    public void setFile(File file)
+    {
+        this.fileName = file.getAbsolutePath();
+    }
+
+    public void setFileName(String fileName)
+    {
+        this.fileName = fileName;
+    }
+
+    /**
+     * Returns the fileName.
+     * 
+     * @return String
+     */
+    public String getFileName()
+    {
+        return fileName;
+    }
+
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+        toXML(document, buffer);
+       return buffer.toString();
+    }
+
+    private void toXML(Node element, StringBuffer buffer)
+       {
+       NodeList nodeList = element.getChildNodes();
+       for (int i = 0; i < nodeList.getLength(); i++)
+        {
+               Node node = nodeList.item(i);
+               if (node instanceof Element)
+            {
+                       buffer.append("<" + node.getNodeName());
+                if (node.hasAttributes())
+                {
+                       NamedNodeMap map = node.getAttributes();
+                    for (int j = 0; j < map.getLength(); j++)
+                    {
+                       Attr attr = (Attr) map.item(j);
+                        buffer.append(" " + attr.getName());
+                        buffer.append("=\"" + attr.getValue() + "\"");
+                    }
+                }
+                buffer.append(">");
+                       toXML(node, buffer);
+                       buffer.append("</" + node.getNodeName() + ">");
+               }
+               else if (node instanceof CharacterData)
+               {
+                       CharacterData data = (CharacterData) node;
+                       buffer.append(data.getData());
+               }
+       }
+    }
 }
Index: src/test/org/apache/commons/configuration/TestCompositeConfiguration.java
===================================================================
RCS file: 
/home/cvs/jakarta-commons/configuration/src/test/org/apache/commons/configuration/TestCompositeConfiguration.java,v
retrieving revision 1.8
diff -u -r1.8 TestCompositeConfiguration.java
--- src/test/org/apache/commons/configuration/TestCompositeConfiguration.java   4 Jun 
2004 12:58:53 -0000       1.8
+++ src/test/org/apache/commons/configuration/TestCompositeConfiguration.java   8 Jul 
2004 11:02:48 -0000
@@ -33,7 +33,7 @@
 {
     protected BasePropertiesConfiguration conf1;
     protected BasePropertiesConfiguration conf2;
-    protected DOM4JConfiguration dom4jConf;
+    protected XMLConfiguration xmlConf;
     protected CompositeConfiguration cc;
 
     /** The File that we test with */
@@ -46,7 +46,7 @@
         cc = new CompositeConfiguration();
         conf1 = new PropertiesConfiguration(testProperties);
         conf2 = new PropertiesConfiguration(testProperties2);
-        dom4jConf = new DOM4JConfiguration(new File(testPropertiesXML));
+        xmlConf = new XMLConfiguration(new File(testPropertiesXML));
     }
 
     public void testAddRemoveConfigurations() throws Exception
@@ -118,13 +118,13 @@
     public void testMultipleTypesOfConfigs() throws Exception
     {
         cc.addConfiguration(conf1);
-        cc.addConfiguration(dom4jConf);
+        cc.addConfiguration(xmlConf);
         assertEquals("Make sure we get the property from conf1 first", 1, 
cc.getInt("test.short"));
         cc.clear();
 
-        cc.addConfiguration(dom4jConf);
+        cc.addConfiguration(xmlConf);
         cc.addConfiguration(conf1);
-        assertEquals("Make sure we get the property from dom4j", 8, 
cc.getInt("test.short"));
+        assertEquals("Make sure we get the property from xml", 8, 
cc.getInt("test.short"));
     }
 
     /**
@@ -133,7 +133,7 @@
     public void testPropertyExistsInOnlyOneConfig() throws Exception
     {
         cc.addConfiguration(conf1);
-        cc.addConfiguration(dom4jConf);
+        cc.addConfiguration(xmlConf);
         assertEquals("value", cc.getString("element"));
     }
 
@@ -143,7 +143,7 @@
     public void testDefaultValueWhenKeyMissing() throws Exception
     {
         cc.addConfiguration(conf1);
-        cc.addConfiguration(dom4jConf);
+        cc.addConfiguration(xmlConf);
         assertEquals("default", cc.getString("bogus", "default"));
         assertTrue(1.4 == cc.getDouble("bogus", 1.4));
         assertTrue(1.4 == cc.getDouble("bogus", 1.4));
@@ -155,9 +155,9 @@
     public void testGettingConfiguration() throws Exception
     {
         cc.addConfiguration(conf1);
-        cc.addConfiguration(dom4jConf);
+        cc.addConfiguration(xmlConf);
         assertEquals(PropertiesConfiguration.class, 
cc.getConfiguration(0).getClass());
-        assertEquals(DOM4JConfiguration.class, cc.getConfiguration(1).getClass());
+        assertEquals(XMLConfiguration.class, cc.getConfiguration(1).getClass());
     }
 
     /**
@@ -166,7 +166,7 @@
     public void testClearingProperty() throws Exception
     {
         cc.addConfiguration(conf1);
-        cc.addConfiguration(dom4jConf);
+        cc.addConfiguration(xmlConf);
         cc.clearProperty("test.short");
         assertTrue("Make sure test.short is gone!", !cc.containsKey("test.short"));
     }
@@ -178,7 +178,7 @@
     public void testAddingProperty() throws Exception
     {
         cc.addConfiguration(conf1);
-        cc.addConfiguration(dom4jConf);
+        cc.addConfiguration(xmlConf);
 
         String[] values = cc.getStringArray("test.short");
 
@@ -200,7 +200,7 @@
     public void testSettingMissingProperty() throws Exception
     {
         cc.addConfiguration(conf1);
-        cc.addConfiguration(dom4jConf);
+        cc.addConfiguration(xmlConf);
         cc.setProperty("my.new.property", "supernew");
         assertEquals("supernew", cc.getString("my.new.property"));
     }
@@ -211,7 +211,7 @@
     public void testGettingSubset() throws Exception
     {
         cc.addConfiguration(conf1);
-        cc.addConfiguration(dom4jConf);
+        cc.addConfiguration(xmlConf);
 
         Configuration subset = null;
         subset = cc.subset("test");
@@ -245,7 +245,7 @@
     public void testList() throws Exception
     {
         cc.addConfiguration(conf1);
-        cc.addConfiguration(dom4jConf);
+        cc.addConfiguration(xmlConf);
 
         List packages = cc.getList("packages");
         // we should get 3 packages here
@@ -266,7 +266,7 @@
     public void testStringArray() throws Exception
     {
         cc.addConfiguration(conf1);
-        cc.addConfiguration(dom4jConf);
+        cc.addConfiguration(xmlConf);
 
         String[] packages = cc.getStringArray("packages");
         // we should get 3 packages here
Index: 
src/test/org/apache/commons/configuration/TestHierarchicalConfigurationXMLReader.java
===================================================================
RCS file: 
/home/cvs/jakarta-commons/configuration/src/test/org/apache/commons/configuration/TestHierarchicalConfigurationXMLReader.java,v
retrieving revision 1.3
diff -u -r1.3 TestHierarchicalConfigurationXMLReader.java
--- 
src/test/org/apache/commons/configuration/TestHierarchicalConfigurationXMLReader.java  
     27 Feb 2004 17:41:34 -0000      1.3
+++ 
src/test/org/apache/commons/configuration/TestHierarchicalConfigurationXMLReader.java  
     8 Jul 2004 11:02:48 -0000
@@ -1,5 +1,3 @@
-package org.apache.commons.configuration;
-
 /*
  * Copyright 2001-2004 The Apache Software Foundation.
  *
@@ -16,6 +14,8 @@
  * limitations under the License.
  */
 
+package org.apache.commons.configuration;
+
 import java.util.Iterator;
 import java.util.List;
 
@@ -33,15 +33,14 @@
  */
 public class TestHierarchicalConfigurationXMLReader extends TestCase
 {
-    private static final String TEST_FILE =
-    "conf/testHierarchicalDOM4JConfiguration.xml";
+    private static final String TEST_FILE = 
"conf/testHierarchicalXMLConfiguration.xml";
     
     private HierarchicalConfigurationXMLReader parser;
     
     protected void setUp() throws Exception
     {
-        HierarchicalDOM4JConfiguration config =
-        new HierarchicalDOM4JConfiguration();
+        HierarchicalXMLConfiguration config =
+        new HierarchicalXMLConfiguration();
         config.setFileName(TEST_FILE);
         config.load();
         parser = new HierarchicalConfigurationXMLReader(config);
Index: xdocs/changes.xml
===================================================================
RCS file: /home/cvs/jakarta-commons/configuration/xdocs/changes.xml,v
retrieving revision 1.23
diff -u -r1.23 changes.xml
--- xdocs/changes.xml   21 Jun 2004 17:45:29 -0000      1.23
+++ xdocs/changes.xml   8 Jul 2004 11:02:48 -0000
@@ -7,6 +7,13 @@
 
   <body>
     <release version="1.0rc1" date="2004-06-??">
+      <action dev="ebourg" type="update">
+        Removed the DOM4J implementations in favor of the DOM ones.
+        DOMConfiguration has been renamed to XMLConfiguration, and
+        HierarchicalDOMConfiguration to HierarchicalXMLConfiguration. The
+        elements parsed by the ConfigurationFactory have been changed
+        accordingly.
+      </action>
       <action dev="ebourg" type="add">
         Added a save() method to PropertiesConfiguration and save(Writer out),
         save(OutputStream out), save(OutputStream out, String encoding) to
Index: xdocs/howto_configurationfactory.xml
===================================================================
RCS file: 
/home/cvs/jakarta-commons/configuration/xdocs/howto_configurationfactory.xml,v
retrieving revision 1.2
diff -u -r1.2 howto_configurationfactory.xml
--- xdocs/howto_configurationfactory.xml        28 Mar 2004 19:58:30 -0000      1.2
+++ xdocs/howto_configurationfactory.xml        8 Jul 2004 11:02:48 -0000
@@ -164,7 +164,7 @@
                        <p>
                                To make this XML document part of our global 
configuration we
                                have to modify our configuration definition file to 
also include
-                               the new file. For XML documents the element 
<code>dom4j</code>
+                               the new file. For XML documents the element 
<code>xml</code>
                                can be used so that we have now:
                        </p>
                        <source>
@@ -173,7 +173,7 @@
 
 <configuration>
   <properties fileName="usergui.properties"/>
-  <dom4j fileName="gui.xml"/>
+  <xml fileName="gui.xml"/>
 </configuration>
 ]]>
                        </source>
Index: xdocs/howto_xml.xml
===================================================================
RCS file: /home/cvs/jakarta-commons/configuration/xdocs/howto_xml.xml,v
retrieving revision 1.3
diff -u -r1.3 howto_xml.xml
--- xdocs/howto_xml.xml 22 Jun 2004 10:07:57 -0000      1.3
+++ xdocs/howto_xml.xml 8 Jul 2004 11:02:48 -0000
@@ -103,13 +103,13 @@
 
 <configuration>
   <properties fileName="usergui.properties"/>
-  <dom4j fileName="gui.xml"/>
-  <dom4j fileName="tables.xml"/>
+  <xml fileName="gui.xml"/>
+  <xml fileName="tables.xml"/>
 </configuration>
 ]]>
                        </source>
                        <p>
-                               The additional <code>dom4j</code> element causes the 
document
+                               The additional <code>xml</code> element causes the 
document
                                with the table definitions to be loaded. When we now 
want to
                                read some of the properties we face a problem: the 
syntax for
                                constructing configuration keys we learned so far is 
not
@@ -177,16 +177,16 @@
 
 <configuration>
   <properties fileName="usergui.properties"/>
-  <dom4j fileName="gui.xml"/>
-  <hierarchicalDom4j fileName="tables.xml"/>
+  <xml fileName="gui.xml"/>
+  <hierarchicalXml fileName="tables.xml"/>
 </configuration>
 ]]>
                        </source>
                        <p>
-                               Note that one <code>dom4j</code> element was replaced 
by a
-                               <code>hierarchicalDom4j</code> element. This element 
tells the configuration
+                               Note that one <code>xml</code> element was replaced by 
a
+                               <code>hierarchicalXml</code> element. This element 
tells the configuration
                                factory that not the default class for processing XML 
documents
-                               should be used, but the class 
<code>HierarchicalDOM4JConfiguration</code>.
+                               should be used, but the class 
<code>HierarchicalXMLConfiguration</code>.
                                As the name implies this class is capable of saving the
                                hierarchy of XML documents thus keeping their 
structure.
                        </p>
@@ -350,12 +350,12 @@
 <configuration>
   <override>
     <properties fileName="usergui.properties"/>
-    <dom4j fileName="gui.xml"/>
+    <xml fileName="gui.xml"/>
   </override>
   
   <additional>
-    <hierarchicalDom4j fileName="tables.xml"/>
-    <hierarchicalDom4j fileName="tasktables.xml" at="tables"/>
+    <hierarchicalXml fileName="tables.xml"/>
+    <hierarchicalXml fileName="tasktables.xml" at="tables"/>
   </additional>
 </configuration>
 ]]>
@@ -378,7 +378,7 @@
                <p>
                        It is the <code>additonal</code> section that introduces a new 
behaviour.
                        All configuration sources listed here are combined to a union 
configuration.
-                       In our example we have put two <code>dom4j</code> elements in 
this area
+                       In our example we have put two <code>xml</code> elements in 
this area
                        that load the available files with database table definitions. 
The syntax
                        of elements in the <code>additional</code> section is 
analogous to the
                        syntax described so far. The only difference is an 
additionally supported
@@ -877,13 +877,13 @@
 <configuration>
   <override>
     <properties fileName="usergui.properties"/>
-    <dom4j fileName="gui.xml"/>
+    <xml fileName="gui.xml"/>
   </override>
   
   <additional>
-    <hierarchicalDom4j fileName="tables.xml"/>
-    <hierarchicalDom4j fileName="tasktables.xml" at="tables"/>
-    <hierarchicalDom4j fileName="connection.xml"/>
+    <hierarchicalXml fileName="tables.xml"/>
+    <hierarchicalXml fileName="tasktables.xml" at="tables"/>
+    <hierarchicalXml fileName="connection.xml"/>
   </additional>
 </configuration>
 ]]>
@@ -929,8 +929,8 @@
                                                The problem here is the loss of 
information concerning the
                                                structure of the properties (as was 
explained in an earlier secion). 
                                                So if you read a configuration source
-                                               using the <code>dom4j</code> element 
rather than the
-                                               <code>hierarchicalDom4j</code> 
element, XML documents
+                                               using the <code>xml</code> element 
rather than the
+                                               <code>hierarchicalXml</code> element, 
XML documents
                                                generated by 
<code>ConfigurationXMLDocument</code> may
                                                look wired; the same is true for 
<code>properties</code>
                                                elements.
Index: xdocs/overview.xml
===================================================================
RCS file: /home/cvs/jakarta-commons/configuration/xdocs/overview.xml,v
retrieving revision 1.3
diff -u -r1.3 overview.xml
--- xdocs/overview.xml  30 Jan 2004 14:05:00 -0000      1.3
+++ xdocs/overview.xml  8 Jul 2004 11:02:48 -0000
@@ -18,16 +18,16 @@
       <subsection name="Configuration Sources">
       <p>
         Currently there are quite a number of different sources of Configuration 
objects.  But,
-        by just using a Configuration object versus a specific type like 
XmlConfiguration or
+        by just using a Configuration object versus a specific type like 
XMLConfiguration or
         JNDIConfiguration, you are sheltered from the mechanics of actually 
retrieving the 
-        configuration values.  These various sources include:
+        configuration values. These various sources include:
         <ul>
           <li>
               <strong>PropertiesConfiguration</strong>
               Loads configuration values from a properties file.
           </li>
           <li>
-              <strong>BasePropertiesConfiguration</strong>
+              <strong>BaseConfiguration</strong>
               An in-memory method of populating a Configuration object.
           </li>
           <li>
@@ -36,8 +36,8 @@
               object.
           </li>
           <li>
-              <strong>DOM4JConfiguration</strong>
-              Takes values from an XML documentation using DOM4J.
+              <strong>XMLConfiguration</strong>
+              Takes values from an XML document.
           </li>
           <li>
               <strong>JNDIConfiguration</strong>
@@ -55,8 +55,6 @@
         this is a very rigid way of doing things.  Instead, with the 
CompositeConfiguration you can
         provide many different ways of setting up a configuration.  You can either do 
it manually (see
         JUnit testcase "TestCompositeConfiguration.java", or via the 
ConfigurationFactory class.
-              
-              
       </p>
       <p>
         Using the ConfigurationFactory, (see the Junit testcase 
"TestConfigurationFactory.java") you load
@@ -69,13 +67,13 @@
 <configuration>
   <jndi className="org.apache.commons.configuration.JNDIConfiguration" 
prefix="java:comp/env"/>
   <properties className="org.apache.commons.configuration.PropertiesConfiguration" 
fileName="conf/test.properties"/>
-  <dom4j className="org.apache.commons.configuration.DOM4JConfiguration" 
fileName="conf/test.xml"/>
+  <xml className="org.apache.commons.configuration.XMLConfiguration" 
fileName="conf/test.xml"/>
 </configuration>
 ]]>   
         </source>
         
         What this says is that we are loading up all JNDI values under java:comp/env 
key, as well 
-        as a properties file in conf/test.properties as well as a dom4j XML file in 
conf/test.xml.  
+        as a properties file in conf/test.properties as well as a XML file in 
conf/test.xml.
         Please inspect the test cases and the files in the conf/ directory for more 
information on how
         to structure your configuration xml file..
       </p>
@@ -106,7 +104,7 @@
       <subsection name="XML Properties File">
         <source>
 <![CDATA[       
-  <dom4j className="org.apache.commons.configuration.DOM4JConfiguration" 
fileName="conf/test.xml"/>
+  <xml className="org.apache.commons.configuration.XMLConfiguration" 
fileName="conf/test.xml"/>
 ]]>   
         </source>     
         <p>

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to