View Javadoc

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 }