ebourg 2004/07/21 05:38:56
Modified: configuration/src/java/org/apache/commons/configuration
XMLConfiguration.java
Log:
Fixed bugs 30074, 30205, 30209 and 30212
Revision Changes Path
1.7 +128 -68
jakarta-commons/configuration/src/java/org/apache/commons/configuration/XMLConfiguration.java
Index: XMLConfiguration.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/configuration/src/java/org/apache/commons/configuration/XMLConfiguration.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- XMLConfiguration.java 13 Jul 2004 14:08:47 -0000 1.6
+++ XMLConfiguration.java 21 Jul 2004 12:38:56 -0000 1.7
@@ -21,22 +21,32 @@
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
import java.io.Writer;
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 javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Attr;
+import org.w3c.dom.CDATASection;
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.w3c.dom.Text;
import org.xml.sax.SAXException;
/**
@@ -54,13 +64,14 @@
* @author J�rg Schaible
* @author <a href="mailto:[EMAIL PROTECTED]">Kelvin Tan</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Daniel Rall</a>
+ * @author Emmanuel Bourg
* @version $Revision$, $Date$
*/
public class XMLConfiguration extends BasePathConfiguration
{
// For conformance with xpath
- private static final char ATTRIB_MARKER = '@';
- private static final String ATTRIB_START_MARKER = "[" + ATTRIB_MARKER;
+ private static final String ATTRIBUTE_START = "[@";
+ private static final String ATTRIBUTE_END = "]";
/**
* For consistency with properties files. Access nodes via an
@@ -91,9 +102,12 @@
{
// build an empty document.
DocumentBuilder builder = null;
- try {
+ try
+ {
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
- } catch (ParserConfigurationException e) {
+ }
+ catch (ParserConfigurationException e)
+ {
throw new ConfigurationRuntimeException(e.getMessage(), e);
}
@@ -183,24 +197,24 @@
Node node = list.item(i);
if (node instanceof Element)
{
- StringBuffer subhierarchy = new StringBuffer(hierarchy.toString());
Element child = (Element) node;
+
+ StringBuffer subhierarchy = new StringBuffer(hierarchy.toString());
subhierarchy.append(child.getTagName());
processAttributes(subhierarchy.toString(), child);
- initProperties(child,
- new StringBuffer(subhierarchy.toString()).append('.'));
+ initProperties(child, subhierarchy.append(NODE_DELIMITER));
}
- else if (node instanceof CharacterData)
+ else if (node instanceof CDATASection || node instanceof Text)
{
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);
+ super.addProperty(hierarchy.substring(0, hierarchy.length() - 1), text);
}
}
@@ -213,12 +227,12 @@
*/
private void processAttributes(String hierarchy, Element element)
{
- // Add attributes as x.y{ATTRIB_START_MARKER}att{ATTRIB_END_MARKER}
+ // Add attributes as x.y{ATTRIBUTE_START}att{ATTRIBUTE_END}
NamedNodeMap attributes = element.getAttributes();
for (int i = 0; i < attributes.getLength(); ++i)
{
Attr attr = (Attr) attributes.item(i);
- String attrName = hierarchy + '[' + ATTRIB_MARKER + attr.getName() +
']';
+ String attrName = hierarchy + ATTRIBUTE_START + attr.getName() +
ATTRIBUTE_END;
super.addProperty(attrName, attr.getValue());
}
}
@@ -260,18 +274,14 @@
*/
private void setXmlProperty(String name, Object value)
{
- String[] nodes = StringUtils.split(name, NODE_DELIMITER);
- String attName = null;
+ // parse the key
+ String[] nodes = parseElementNames(name);
+ String attName = parseAttributeName(name);
+
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();
@@ -290,7 +300,7 @@
}
// 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)
+ if (child == null)
{
child = document.createElement(eName);
element.appendChild(child);
@@ -324,20 +334,16 @@
private void clearXmlProperty(String name)
{
- String[] nodes = StringUtils.split(name, NODE_DELIMITER);
- String attName = null;
+ // parse the key
+ String[] nodes = parseElementNames(name);
+ String attName = parseAttributeName(name);
+
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++) {
@@ -448,7 +454,7 @@
*
* @param out the output stream used to save the configuration
*/
- public void save(OutputStream out) throws IOException
+ public void save(OutputStream out) throws ConfigurationException
{
save(out, null);
}
@@ -459,10 +465,17 @@
* @param out the output stream used to save the configuration
* @param encoding the charset used to write the configuration
*/
- public void save(OutputStream out, String encoding) throws IOException
+ public void save(OutputStream out, String encoding) throws
ConfigurationException
{
- OutputStreamWriter writer = new OutputStreamWriter(out, encoding);
- save(writer);
+ try
+ {
+ OutputStreamWriter writer = new OutputStreamWriter(out, encoding);
+ save(writer);
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ throw new ConfigurationException(e.getMessage(), e);
+ }
}
/**
@@ -470,9 +483,21 @@
*
* @param writer the output stream used to save the configuration
*/
- public void save(Writer writer) throws IOException
+ public void save(Writer writer) throws ConfigurationException
{
- writer.write(toString());
+ try
+ {
+ Transformer transformer =
TransformerFactory.newInstance().newTransformer();
+ Source source = new DOMSource(document);
+ Result result = new StreamResult(writer);
+
+ transformer.setOutputProperty("indent", "yes");
+ transformer.transform(source, result);
+ }
+ catch (TransformerException e)
+ {
+ throw new ConfigurationException(e.getMessage(), e);
+ }
}
/**
@@ -510,40 +535,75 @@
return fileName;
}
- public String toString() {
- StringBuffer buffer = new StringBuffer();
- toXML(document, buffer);
- return buffer.toString();
+ public String toString()
+ {
+ StringWriter writer = new StringWriter();
+ try
+ {
+ save(writer);
+ }
+ catch (ConfigurationException e)
+ {
+ e.printStackTrace();
+ }
+ return writer.toString();
}
- private void toXML(Node element, StringBuffer buffer)
- {
- NodeList nodeList = element.getChildNodes();
- for (int i = 0; i < nodeList.getLength(); i++)
+ /**
+ * Parse a property key and return an array of the element hierarchy it
+ * specifies. For example the key "[EMAIL PROTECTED]" will result in [x, y, z].
+ *
+ * @param key the key to parse
+ *
+ * @return the elements in the key
+ */
+ protected static String[] parseElementNames(String key)
+ {
+ if (key == null)
{
- Node node = nodeList.item(i);
- if (node instanceof Element)
+ return new String[] {};
+ }
+ else
+ {
+ // find the beginning of the attribute name
+ int attStart = key.indexOf(ATTRIBUTE_START);
+
+ if (attStart > -1)
{
- 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());
- }
- }
+ // remove the attribute part of the key
+ key = key.substring(0, attStart);
+ }
+
+ return StringUtils.split(key, NODE_DELIMITER);
+ }
+ }
+
+ /**
+ * Parse a property key and return the attribute name if it existst.
+ *
+ * @param key the key to parse
+ *
+ * @return the attribute name, or null if the key doesn't contain one
+ */
+ protected static String parseAttributeName(String key)
+ {
+ String name = null;
+
+ if (key != null)
+ {
+ // find the beginning of the attribute name
+ int attStart = key.indexOf(ATTRIBUTE_START);
+
+ if (attStart > -1)
+ {
+ // find the end of the attribute name
+ int attEnd = key.indexOf(ATTRIBUTE_END);
+ attEnd = attEnd > -1 ? attEnd : key.length();
+
+ name = key.substring(attStart + ATTRIBUTE_START.length(), attEnd);
+ }
+ }
+
+ return name;
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]