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]