001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.commons.configuration;
019:
020: import java.util.Iterator;
021:
022: import org.apache.commons.configuration.HierarchicalConfiguration.Node;
023: import org.xml.sax.Attributes;
024: import org.xml.sax.helpers.AttributesImpl;
025:
026: /**
027: * <p>A specialized SAX2 XML parser that "parses" hierarchical
028: * configuration objects.</p>
029: * <p>This class mimics to be a SAX conform XML parser. Instead of parsing
030: * XML documents it processes a <code>Configuration</code> object and
031: * generates SAX events for the single properties defined there. This enables
032: * the whole world of XML processing for configuration objects.</p>
033: * <p>The <code>HierarchicalConfiguration</code> object to be parsed can be
034: * specified using a constructor or the <code>setConfiguration()</code> method.
035: * This object will be processed by the <code>parse()</code> methods. Note
036: * that these methods ignore their argument.</p>
037: *
038: * @author <a href="mailto:oliver.heger@t-online.de">Oliver Heger</a>
039: * @version $Id: HierarchicalConfigurationXMLReader.java 439648 2006-09-02 20:42:10Z oheger $
040: */
041: public class HierarchicalConfigurationXMLReader extends
042: ConfigurationXMLReader {
043: /** Stores the configuration object to be parsed.*/
044: private HierarchicalConfiguration configuration;
045:
046: /**
047: * Creates a new instance of
048: * <code>HierarchicalConfigurationXMLReader</code>.
049: */
050: public HierarchicalConfigurationXMLReader() {
051: super ();
052: }
053:
054: /**
055: * Creates a new instance of
056: * <code>HierarchicalConfigurationXMLReader</code> and sets the
057: * configuration to be parsed.
058: *
059: * @param config the configuration object
060: */
061: public HierarchicalConfigurationXMLReader(
062: HierarchicalConfiguration config) {
063: this ();
064: setConfiguration(config);
065: }
066:
067: /**
068: * Returns the configuration object to be parsed.
069: *
070: * @return the configuration object to be parsed
071: */
072: public HierarchicalConfiguration getConfiguration() {
073: return configuration;
074: }
075:
076: /**
077: * Sets the configuration object to be parsed.
078: *
079: * @param config the configuration object to be parsed
080: */
081: public void setConfiguration(HierarchicalConfiguration config) {
082: configuration = config;
083: }
084:
085: /**
086: * Returns the configuration object to be processed.
087: *
088: * @return the actual configuration object
089: */
090: public Configuration getParsedConfiguration() {
091: return getConfiguration();
092: }
093:
094: /**
095: * Processes the actual configuration object to generate SAX parsing events.
096: */
097: protected void processKeys() {
098: getConfiguration().getRoot().visit(new SAXVisitor(), null);
099: }
100:
101: /**
102: * A specialized visitor class for generating SAX events for a
103: * hierarchical node structure.
104: *
105: */
106: class SAXVisitor extends HierarchicalConfiguration.NodeVisitor {
107: /** Constant for the attribute type.*/
108: private static final String ATTR_TYPE = "CDATA";
109:
110: /**
111: * Visits the specified node after its children have been processed.
112: *
113: * @param node the actual node
114: * @param key the key of this node
115: */
116: public void visitAfterChildren(Node node, ConfigurationKey key) {
117: if (!isAttributeNode(node)) {
118: fireElementEnd(nodeName(node));
119: }
120: }
121:
122: /**
123: * Visits the specified node.
124: *
125: * @param node the actual node
126: * @param key the key of this node
127: */
128: public void visitBeforeChildren(Node node, ConfigurationKey key) {
129: if (!isAttributeNode(node)) {
130: fireElementStart(nodeName(node), fetchAttributes(node));
131:
132: if (node.getValue() != null) {
133: fireCharacters(node.getValue().toString());
134: }
135: }
136: }
137:
138: /**
139: * Checks if iteration should be terminated. This implementation stops
140: * iteration after an exception has occurred.
141: *
142: * @return a flag if iteration should be stopped
143: */
144: public boolean terminate() {
145: return getException() != null;
146: }
147:
148: /**
149: * Returns an object with all attributes for the specified node.
150: *
151: * @param node the actual node
152: * @return an object with all attributes of this node
153: */
154: protected Attributes fetchAttributes(Node node) {
155: AttributesImpl attrs = new AttributesImpl();
156:
157: for (Iterator it = node.getAttributes().iterator(); it
158: .hasNext();) {
159: Node child = (Node) it.next();
160: if (child.getValue() != null) {
161: String attr = child.getName();
162: attrs.addAttribute(NS_URI, attr, attr, ATTR_TYPE,
163: child.getValue().toString());
164: }
165: }
166:
167: return attrs;
168: }
169:
170: /**
171: * Helper method for determining the name of a node. If a node has no
172: * name (which is true for the root node), the specified default name
173: * will be used.
174: *
175: * @param node the node to be checked
176: * @return the name for this node
177: */
178: private String nodeName(Node node) {
179: return (node.getName() == null) ? getRootName() : node
180: .getName();
181: }
182:
183: /**
184: * Checks if the specified node is an attribute node. In the node
185: * hierarchy attributes are stored as normal child nodes, but with
186: * special names.
187: *
188: * @param node the node to be checked
189: * @return a flag if this is an attribute node
190: */
191: private boolean isAttributeNode(Node node) {
192: return node.isAttribute();
193: }
194: }
195: }
|