View Javadoc

1   /*
2    * Copyright 2001-2004 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License")
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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 }