1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.configuration;
19
20 import java.util.Iterator;
21
22 import org.apache.commons.configuration.HierarchicalConfiguration.Node;
23 import org.xml.sax.Attributes;
24 import org.xml.sax.helpers.AttributesImpl;
25
26 /***
27 * <p>A specialized SAX2 XML parser that "parses" hierarchical
28 * configuration objects.</p>
29 * <p>This class mimics to be a SAX conform XML parser. Instead of parsing
30 * XML documents it processes a <code>Configuration</code> object and
31 * generates SAX events for the single properties defined there. This enables
32 * the whole world of XML processing for configuration objects.</p>
33 * <p>The <code>HierarchicalConfiguration</code> object to be parsed can be
34 * specified using a constructor or the <code>setConfiguration()</code> method.
35 * This object will be processed by the <code>parse()</code> methods. Note
36 * that these methods ignore their argument.</p>
37 *
38 * @author <a href="mailto:oliver.heger@t-online.de">Oliver Heger</a>
39 * @version $Id: HierarchicalConfigurationXMLReader.java 439648 2006-09-02 20:42:10Z oheger $
40 */
41 public class HierarchicalConfigurationXMLReader extends ConfigurationXMLReader
42 {
43 /*** Stores the configuration object to be parsed.*/
44 private HierarchicalConfiguration configuration;
45
46 /***
47 * Creates a new instance of
48 * <code>HierarchicalConfigurationXMLReader</code>.
49 */
50 public HierarchicalConfigurationXMLReader()
51 {
52 super();
53 }
54
55 /***
56 * Creates a new instance of
57 * <code>HierarchicalConfigurationXMLReader</code> and sets the
58 * configuration to be parsed.
59 *
60 * @param config the configuration object
61 */
62 public HierarchicalConfigurationXMLReader(HierarchicalConfiguration config)
63 {
64 this();
65 setConfiguration(config);
66 }
67
68 /***
69 * Returns the configuration object to be parsed.
70 *
71 * @return the configuration object to be parsed
72 */
73 public HierarchicalConfiguration getConfiguration()
74 {
75 return configuration;
76 }
77
78 /***
79 * Sets the configuration object to be parsed.
80 *
81 * @param config the configuration object to be parsed
82 */
83 public void setConfiguration(HierarchicalConfiguration config)
84 {
85 configuration = config;
86 }
87
88 /***
89 * Returns the configuration object to be processed.
90 *
91 * @return the actual configuration object
92 */
93 public Configuration getParsedConfiguration()
94 {
95 return getConfiguration();
96 }
97
98 /***
99 * Processes the actual configuration object to generate SAX parsing events.
100 */
101 protected void processKeys()
102 {
103 getConfiguration().getRoot().visit(new SAXVisitor(), null);
104 }
105
106 /***
107 * A specialized visitor class for generating SAX events for a
108 * hierarchical node structure.
109 *
110 */
111 class SAXVisitor extends HierarchicalConfiguration.NodeVisitor
112 {
113 /*** Constant for the attribute type.*/
114 private static final String ATTR_TYPE = "CDATA";
115
116 /***
117 * Visits the specified node after its children have been processed.
118 *
119 * @param node the actual node
120 * @param key the key of this node
121 */
122 public void visitAfterChildren(Node node, ConfigurationKey key)
123 {
124 if (!isAttributeNode(node))
125 {
126 fireElementEnd(nodeName(node));
127 }
128 }
129
130 /***
131 * Visits the specified node.
132 *
133 * @param node the actual node
134 * @param key the key of this node
135 */
136 public void visitBeforeChildren(Node node, ConfigurationKey key)
137 {
138 if (!isAttributeNode(node))
139 {
140 fireElementStart(nodeName(node), fetchAttributes(node));
141
142 if (node.getValue() != null)
143 {
144 fireCharacters(node.getValue().toString());
145 }
146 }
147 }
148
149 /***
150 * Checks if iteration should be terminated. This implementation stops
151 * iteration after an exception has occurred.
152 *
153 * @return a flag if iteration should be stopped
154 */
155 public boolean terminate()
156 {
157 return getException() != null;
158 }
159
160 /***
161 * Returns an object with all attributes for the specified node.
162 *
163 * @param node the actual node
164 * @return an object with all attributes of this node
165 */
166 protected Attributes fetchAttributes(Node node)
167 {
168 AttributesImpl attrs = new AttributesImpl();
169
170 for (Iterator it = node.getAttributes().iterator(); it.hasNext();)
171 {
172 Node child = (Node) it.next();
173 if (child.getValue() != null)
174 {
175 String attr = child.getName();
176 attrs.addAttribute(NS_URI, attr, attr, ATTR_TYPE, child.getValue().toString());
177 }
178 }
179
180 return attrs;
181 }
182
183 /***
184 * Helper method for determining the name of a node. If a node has no
185 * name (which is true for the root node), the specified default name
186 * will be used.
187 *
188 * @param node the node to be checked
189 * @return the name for this node
190 */
191 private String nodeName(Node node)
192 {
193 return (node.getName() == null) ? getRootName() : node.getName();
194 }
195
196 /***
197 * Checks if the specified node is an attribute node. In the node
198 * hierarchy attributes are stored as normal child nodes, but with
199 * special names.
200 *
201 * @param node the node to be checked
202 * @return a flag if this is an attribute node
203 */
204 private boolean isAttributeNode(Node node)
205 {
206 return node.isAttribute();
207 }
208 }
209 }