1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.configuration;
19
20 import org.apache.commons.configuration.HierarchicalConfiguration.Node;
21 import org.apache.commons.configuration.tree.ConfigurationNode;
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} 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} object to be parsed can be
33 * specified using a constructor or the {@code setConfiguration()} method.
34 * This object will be processed by the {@code parse()} methods. Note
35 * that these methods ignore their argument.</p>
36 *
37 * @author <a
38 * href="http://commons.apache.org/configuration/team-list.html">Commons Configuration team</a>
39 * @version $Id: HierarchicalConfigurationXMLReader.java 1209998 2011-12-03 20:31:16Z 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 {@code HierarchicalConfigurationXMLReader}.
48 */
49 public HierarchicalConfigurationXMLReader()
50 {
51 super();
52 }
53
54 /**
55 * Creates a new instance of {@code HierarchicalConfigurationXMLReader} and
56 * sets the configuration to be parsed.
57 *
58 * @param config the configuration object
59 */
60 public HierarchicalConfigurationXMLReader(HierarchicalConfiguration config)
61 {
62 this();
63 setConfiguration(config);
64 }
65
66 /**
67 * Returns the configuration object to be parsed.
68 *
69 * @return the configuration object to be parsed
70 */
71 public HierarchicalConfiguration getConfiguration()
72 {
73 return configuration;
74 }
75
76 /**
77 * Sets the configuration object to be parsed.
78 *
79 * @param config the configuration object to be parsed
80 */
81 public void setConfiguration(HierarchicalConfiguration config)
82 {
83 configuration = config;
84 }
85
86 /**
87 * Returns the configuration object to be processed.
88 *
89 * @return the actual configuration object
90 */
91 @Override
92 public Configuration getParsedConfiguration()
93 {
94 return getConfiguration();
95 }
96
97 /**
98 * Processes the actual configuration object to generate SAX parsing events.
99 */
100 @Override
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 @Override
123 public void visitAfterChildren(Node node, ConfigurationKey key)
124 {
125 if (!isAttributeNode(node))
126 {
127 fireElementEnd(nodeName(node));
128 }
129 }
130
131 /**
132 * Visits the specified node.
133 *
134 * @param node the actual node
135 * @param key the key of this node
136 */
137 @Override
138 public void visitBeforeChildren(Node node, ConfigurationKey key)
139 {
140 if (!isAttributeNode(node))
141 {
142 fireElementStart(nodeName(node), fetchAttributes(node));
143
144 if (node.getValue() != null)
145 {
146 fireCharacters(node.getValue().toString());
147 }
148 }
149 }
150
151 /**
152 * Checks if iteration should be terminated. This implementation stops
153 * iteration after an exception has occurred.
154 *
155 * @return a flag if iteration should be stopped
156 */
157 @Override
158 public boolean terminate()
159 {
160 return getException() != null;
161 }
162
163 /**
164 * Returns an object with all attributes for the specified node.
165 *
166 * @param node the actual node
167 * @return an object with all attributes of this node
168 */
169 protected Attributes fetchAttributes(Node node)
170 {
171 AttributesImpl attrs = new AttributesImpl();
172
173 for (ConfigurationNode child : node.getAttributes())
174 {
175 if (child.getValue() != null)
176 {
177 String attr = child.getName();
178 attrs.addAttribute(NS_URI, attr, attr, ATTR_TYPE, child.getValue().toString());
179 }
180 }
181
182 return attrs;
183 }
184
185 /**
186 * Helper method for determining the name of a node. If a node has no
187 * name (which is true for the root node), the specified default name
188 * will be used.
189 *
190 * @param node the node to be checked
191 * @return the name for this node
192 */
193 private String nodeName(Node node)
194 {
195 return (node.getName() == null) ? getRootName() : node.getName();
196 }
197
198 /**
199 * Checks if the specified node is an attribute node. In the node
200 * hierarchy attributes are stored as normal child nodes, but with
201 * special names.
202 *
203 * @param node the node to be checked
204 * @return a flag if this is an attribute node
205 */
206 private boolean isAttributeNode(Node node)
207 {
208 return node.isAttribute();
209 }
210 }
211 }