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 java.util.Iterator; 021 022 import org.apache.commons.configuration.HierarchicalConfiguration.Node; 023 import org.xml.sax.Attributes; 024 import org.xml.sax.helpers.AttributesImpl; 025 026 /** 027 * <p>A specialized SAX2 XML parser that "parses" hierarchical 028 * configuration objects.</p> 029 * <p>This class mimics to be a SAX conform XML parser. Instead of parsing 030 * XML documents it processes a <code>Configuration</code> object and 031 * generates SAX events for the single properties defined there. This enables 032 * the whole world of XML processing for configuration objects.</p> 033 * <p>The <code>HierarchicalConfiguration</code> object to be parsed can be 034 * specified using a constructor or the <code>setConfiguration()</code> method. 035 * This object will be processed by the <code>parse()</code> methods. Note 036 * that these methods ignore their argument.</p> 037 * 038 * @author <a href="mailto:oliver.heger@t-online.de">Oliver Heger</a> 039 * @version $Id: HierarchicalConfigurationXMLReader.java 439648 2006-09-02 20:42:10Z 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 048 * <code>HierarchicalConfigurationXMLReader</code>. 049 */ 050 public HierarchicalConfigurationXMLReader() 051 { 052 super(); 053 } 054 055 /** 056 * Creates a new instance of 057 * <code>HierarchicalConfigurationXMLReader</code> and sets the 058 * configuration to be parsed. 059 * 060 * @param config the configuration object 061 */ 062 public HierarchicalConfigurationXMLReader(HierarchicalConfiguration config) 063 { 064 this(); 065 setConfiguration(config); 066 } 067 068 /** 069 * Returns the configuration object to be parsed. 070 * 071 * @return the configuration object to be parsed 072 */ 073 public HierarchicalConfiguration getConfiguration() 074 { 075 return configuration; 076 } 077 078 /** 079 * Sets the configuration object to be parsed. 080 * 081 * @param config the configuration object to be parsed 082 */ 083 public void setConfiguration(HierarchicalConfiguration config) 084 { 085 configuration = config; 086 } 087 088 /** 089 * Returns the configuration object to be processed. 090 * 091 * @return the actual configuration object 092 */ 093 public Configuration getParsedConfiguration() 094 { 095 return getConfiguration(); 096 } 097 098 /** 099 * Processes the actual configuration object to generate SAX parsing events. 100 */ 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 public void visitAfterChildren(Node node, ConfigurationKey key) 123 { 124 if (!isAttributeNode(node)) 125 { 126 fireElementEnd(nodeName(node)); 127 } 128 } 129 130 /** 131 * Visits the specified node. 132 * 133 * @param node the actual node 134 * @param key the key of this node 135 */ 136 public void visitBeforeChildren(Node node, ConfigurationKey key) 137 { 138 if (!isAttributeNode(node)) 139 { 140 fireElementStart(nodeName(node), fetchAttributes(node)); 141 142 if (node.getValue() != null) 143 { 144 fireCharacters(node.getValue().toString()); 145 } 146 } 147 } 148 149 /** 150 * Checks if iteration should be terminated. This implementation stops 151 * iteration after an exception has occurred. 152 * 153 * @return a flag if iteration should be stopped 154 */ 155 public boolean terminate() 156 { 157 return getException() != null; 158 } 159 160 /** 161 * Returns an object with all attributes for the specified node. 162 * 163 * @param node the actual node 164 * @return an object with all attributes of this node 165 */ 166 protected Attributes fetchAttributes(Node node) 167 { 168 AttributesImpl attrs = new AttributesImpl(); 169 170 for (Iterator it = node.getAttributes().iterator(); it.hasNext();) 171 { 172 Node child = (Node) it.next(); 173 if (child.getValue() != null) 174 { 175 String attr = 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 node.isAttribute(); 207 } 208 } 209 }