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