Coverage details for org.chwf.config.XMLDigester

LineHitsSource
1 /*
2 Chrysalis Web Framework [http://chrysalis.sourceforge.net]
3 Copyright (c) 2002, 2003, 2004, Paul Strack
4  
5 All rights reserved.
6  
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9  
10 1. Redistributions of source code must retain the above copyright notice, this
11 list of conditions and the following disclaimer.
12  
13 2. Redistributions in binary form must reproduce the above copyright notice,
14 this list of conditions and the following disclaimer in the documentation
15 and/or other materials provided with the distribution.
16  
17 3. Neither the name of the copyright holder nor the names of its contributors
18 may be used to endorse or promote products derived from this software without
19 specific prior written permission.
20  
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
25 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
28 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32  
33 package org.chwf.config;
34  
35 import java.util.HashMap;
36 import java.util.LinkedList;
37 import java.util.List;
38 import java.util.Map;
39  
40 import org.chwf.util.SequencedHashMap;
41 import org.xml.sax.Attributes;
42 import org.xml.sax.helpers.DefaultHandler;
43  
44 /**
45  * Converts XML file data to a hash map, with keys based on the Xpath,
46  * omitting the root tag.
47  *
48  * @author <a href="mailto:pfstrack@users.sourceforge.net">Paul Strack</a>
49  */
50404class XMLDigester extends DefaultHandler {
51  
52   /** Property value XML attribute. */
53   private static final String PROPERTY_ATTRIBUTE = "value";
54  
55   /** Property name XML attribute. */
56   private static final String NAME_ATTRIBUTE = "name";
57  
58   /** Character delimiting sub-names in configuration keys. */
59   private static final char KEY_SEPARATOR = '.';
60  
61   /** Null character. */
62   private static final char NULL_CHAR = '\u0000';
63  
64   /** Map containing configuration data. */
65202  private Map data = new SequencedHashMap();
66  
67   /** Map tracking duplicate elements. */
68202  private Map duplicateCount = new HashMap();
69  
70   /** Current element path being processed. */
71202  private List path = new LinkedList();
72  
73   /** Current property value. */
74202  private String propertyValue = null;
75  
76   /** StringBuffer (reused). */
77202  private StringBuffer buffer = new StringBuffer();
78  
79   /** Flag indicating whether parser is current inside a tag. */
80202  private boolean inTag = false;
81  
82   /**
83    * Called at the start tag. Sets up for property retrieval.
84    *
85    * @param namespaceURI The namespace URI.
86    * @param localName The local name (without prefix).
87    * @param qName The qualified name (with prefix).
88    * @param atts The attributes attached to the element.
89    */
90   public void startElement(
91     String namespaceURI,
92     String localName,
93     String qName,
94     Attributes atts) {
95  
969041    inTag = true;
97  
98     // Push tag name into path:
999041    String name = atts.getValue(NAME_ATTRIBUTE);
1009041    if (name != null) {
1017799      path.add(name); // Add name attribute
102     } else {
1031242      path.add(qName); // Add tag name
104     }
105  
106     // Set property to value of property attribute, if any:
1079041    propertyValue = atts.getValue(PROPERTY_ATTRIBUTE);
1089041    if (propertyValue != null) {
109110      addProperty();
110     }
111     
112     // Add properties for other attributes
11322753    for (int i = 0; i < atts.getLength(); i++) {
11413712      String att = atts.getQName(i);
11513712      if (!att.equals(NAME_ATTRIBUTE) && !att.equals(PROPERTY_ATTRIBUTE)) {
1165803        propertyValue = atts.getValue(i);
1175803        path.add(att);
1185803        addProperty();
1195803        path.remove(att);
1205803        propertyValue = null;
121       }
122     }
123  
124     // Clear buffer before adding tag contents:
1259041    buffer.setLength(0);
1269041  }
127  
128   /**
129    * Called for characters. Stores char data in buffer.
130    *
131    * @param ch The characters from the XML document.
132    * @param start The start position in the array.
133    * @param length The number of characters to read from the array.
134    */
135   public void characters(char[] ch, int start, int length) {
13613907    if (textIsNeeded()) {
1375051      buffer.append(ch, start, length); // Add text to buffer
138     }
13913907  }
140  
141   /**
142    * Called at the end tag. Save property value.
143    *
144    * @param namespaceURI The namespace URI.
145    * @param localName The local name (without prefix).
146    * @param qName The qualified name (with prefix).
147    */
148   public void endElement(String namespaceURI, String localName, String qName) {
149     // Retrieve the buffer, if need:
1509041    if (textIsNeeded() && (buffer.length() > 0)) {
1511473      propertyValue = buffer.toString();
1521473      addProperty();
153     }
154  
155     // Clean up data:
1569041    propertyValue = null;
1579041    inTag = false;
158  
159     // Pop last name in path:
1609041    path.remove(path.size() - 1);
1619041  }
162  
163   /**
164    * Retrieve the finished data map. Use this after parsing finishes.
165    *
166    * @return The map holding accumulated data.
167    */
168   public Map getData() {
169202    return this.data;
170   }
171  
172   /**
173    * True if in a tag and a property has not been set yet.
174    *
175    * @return Whether tag text is needed.
176    */
177   private boolean textIsNeeded() {
17822948    return inTag && (propertyValue == null);
179   }
180  
181   /** Add property to the hashmap, converting the path to a dot-separate key. */
182   private void addProperty() {
1837386    String propertyName = derivePropertyName();
1847386    if (data.get(propertyName) == null) {
1855979      data.put(propertyName, propertyValue); // Store property
186     } else { // Duplicate property
1871407      Integer count = (Integer) duplicateCount.get(propertyName);
1881407      if (count == null) {
189525        count = new Integer(2);
190       } else {
191882        count = new Integer(count.intValue() + 1);
192       }
1931407      duplicateCount.put(propertyName, count);
1941407      String revisedName =
195         propertyName + KEY_SEPARATOR + NULL_CHAR + (char) count.intValue();
1961407      data.put(revisedName, propertyValue);
197     }
1987386  }
199  
200   /**
201    * Derive property name from current path.
202    *
203    * @return The property name.
204    */
205   private String derivePropertyName() {
2067386    buffer.setLength(0); // Clear buffer
207     
208     // Start loop at 1 to skip root element name:
20931388    for (int i = 1; i < path.size(); i++) {
21024002      buffer.append(path.get(i));
21124002      buffer.append(KEY_SEPARATOR);
212     }
213     
214     // Strip final and extraneous KEY_SEPARATOR:
2157386    if (buffer.length() > 0) {
2167386      buffer.setLength(buffer.length() - 1);
217     }
218     
2197386    String propertyName = buffer.toString();
2207386    return propertyName;
221   }
222 }

this report was generated by version 1.0.5 of jcoverage.
visit www.jcoverage.com for updates.

copyright © 2003, jcoverage ltd. all rights reserved.
Java is a trademark of Sun Microsystems, Inc. in the United States and other countries.