001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.commons.configuration;
019    
020    import org.apache.commons.configuration.HierarchicalConfiguration.Node;
021    import org.apache.commons.configuration.tree.ConfigurationNode;
022    import org.xml.sax.Attributes;
023    import org.xml.sax.helpers.AttributesImpl;
024    
025    /**
026     * <p>A specialized SAX2 XML parser that "parses" hierarchical
027     * configuration objects.</p>
028     * <p>This class mimics to be a SAX conform XML parser. Instead of parsing
029     * XML documents it processes a {@code Configuration} object and
030     * generates SAX events for the single properties defined there. This enables
031     * the whole world of XML processing for configuration objects.</p>
032     * <p>The {@code HierarchicalConfiguration} object to be parsed can be
033     * specified using a constructor or the {@code setConfiguration()} method.
034     * This object will be processed by the {@code parse()} methods. Note
035     * that these methods ignore their argument.</p>
036     *
037     * @author <a
038     * href="http://commons.apache.org/configuration/team-list.html">Commons Configuration team</a>
039     * @version $Id: HierarchicalConfigurationXMLReader.java 1209998 2011-12-03 20:31:16Z oheger $
040     */
041    public class HierarchicalConfigurationXMLReader extends ConfigurationXMLReader
042    {
043        /** Stores the configuration object to be parsed.*/
044        private HierarchicalConfiguration configuration;
045    
046        /**
047         * Creates a new instance of {@code HierarchicalConfigurationXMLReader}.
048         */
049        public HierarchicalConfigurationXMLReader()
050        {
051            super();
052        }
053    
054        /**
055         * Creates a new instance of {@code HierarchicalConfigurationXMLReader} and
056         * sets the configuration to be parsed.
057         *
058         * @param config the configuration object
059         */
060        public HierarchicalConfigurationXMLReader(HierarchicalConfiguration config)
061        {
062            this();
063            setConfiguration(config);
064        }
065    
066        /**
067         * Returns the configuration object to be parsed.
068         *
069         * @return the configuration object to be parsed
070         */
071        public HierarchicalConfiguration getConfiguration()
072        {
073            return configuration;
074        }
075    
076        /**
077         * Sets the configuration object to be parsed.
078         *
079         * @param config the configuration object to be parsed
080         */
081        public void setConfiguration(HierarchicalConfiguration config)
082        {
083            configuration = config;
084        }
085    
086        /**
087         * Returns the configuration object to be processed.
088         *
089         * @return the actual configuration object
090         */
091        @Override
092        public Configuration getParsedConfiguration()
093        {
094            return getConfiguration();
095        }
096    
097        /**
098         * Processes the actual configuration object to generate SAX parsing events.
099         */
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    }