001 /* ======================================================================== 002 * JCommon : a free general purpose class library for the Java(tm) platform 003 * ======================================================================== 004 * 005 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jcommon/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 025 * in the United States and other countries.] 026 * 027 * ----------- 028 * Parser.java 029 * ----------- 030 * (C)opyright 2003-2005, by Thomas Morgner and Contributors. 031 * 032 * Original Author: Thomas Morgner (taquera@sherito.org); 033 * Contributor(s): David Gilbert (for Object Refinery Limited); 034 * 035 * $Id: Parser.java,v 1.9 2008/09/10 09:20:49 mungady Exp $ 036 * 037 * Changes 038 * ------- 039 * 09-Jan-2003 : Initial version. 040 * 29-Apr-2003 : Distilled from the JFreeReport project and moved into JCommon 041 * 14-Jul-2003 : More help with the error location given by catching all exceptions. 042 * 043 */ 044 045 package org.jfree.xml; 046 047 import java.util.HashMap; 048 import java.util.Stack; 049 050 import org.xml.sax.Attributes; 051 import org.xml.sax.SAXException; 052 053 /** 054 * The Parser handles the SAXEvents and forwards the event call to the currently 055 * active ElementDefinitionHandler. Contains methods to manage and 056 * configure the parsing process. 057 * <p> 058 * An initial report definition handler must be set before the parser can be used. 059 * 060 * @author Thomas Morgner 061 */ 062 public abstract class Parser extends FrontendDefaultHandler { 063 064 /** A key for the content base. */ 065 public static final String CONTENTBASE_KEY = "content-base"; 066 067 /** A stack for the active factories. */ 068 private Stack activeFactories; 069 070 /** The initial factory. */ 071 private ElementDefinitionHandler initialFactory; 072 073 /** Storage for temporary objects and factories used during the parsing process. */ 074 private HashMap parserHelperObjects; 075 076 /** 077 * Creates a new parser. 078 */ 079 public Parser() { 080 this.activeFactories = new Stack(); 081 this.parserHelperObjects = new HashMap(); 082 } 083 084 /** 085 * Returns the currently collected comments. 086 * @return the comments. 087 */ 088 public String[] getComments() { 089 return getCommentHandler().getComments(); 090 } 091 092 /** 093 * Pushes a handler onto the stack. 094 * 095 * @param factory the handler. 096 */ 097 public void pushFactory(final ElementDefinitionHandler factory) { 098 this.activeFactories.push(factory); 099 } 100 101 /** 102 * Reads a handler off the stack without removing it. 103 * 104 * @return The handler. 105 */ 106 public ElementDefinitionHandler peekFactory() { 107 return (ElementDefinitionHandler) this.activeFactories.peek(); 108 } 109 110 /** 111 * Pops a handler from the stack. 112 * 113 * @return The handler. 114 */ 115 public ElementDefinitionHandler popFactory() { 116 this.activeFactories.pop(); 117 return peekFactory(); 118 } 119 120 /** 121 * Receive notification of the end of the document. 122 * 123 * <p>By default, do nothing. Application writers may override this 124 * method in a subclass to take specific actions at the end 125 * of a document (such as finalising a tree or closing an output 126 * file).</p> 127 * 128 * @exception SAXException Any SAX exception, possibly wrapping another exception. 129 * 130 * @see org.xml.sax.ContentHandler#endDocument 131 */ 132 public void endDocument() throws SAXException { 133 // ignored 134 } 135 136 /** 137 * Receive notification of the beginning of the document. 138 * 139 * <p>By default, do nothing. Application writers may override this 140 * method in a subclass to take specific actions at the beginning 141 * of a document (such as allocating the root node of a tree or 142 * creating an output file).</p> 143 * 144 * @exception SAXException Any SAX exception, possibly wrapping another exception. 145 * @see org.xml.sax.ContentHandler#startDocument 146 */ 147 public void startDocument() throws SAXException { 148 this.activeFactories.clear(); 149 pushFactory(getInitialFactory()); 150 } 151 152 /** 153 * Receive notification of character data inside an element. 154 * 155 * <p>By default, do nothing. Application writers may override this 156 * method to take specific actions for each chunk of character data 157 * (such as adding the data to a node or buffer, or printing it to 158 * a file).</p> 159 * 160 * @param ch the characters. 161 * @param start the start position in the character array. 162 * @param length the number of characters to use from the character array. 163 * 164 * @exception SAXException Any SAX exception, possibly wrapping another exception. 165 * @see org.xml.sax.ContentHandler#characters 166 */ 167 public void characters(final char[] ch, final int start, final int length) 168 throws SAXException { 169 try { 170 peekFactory().characters(ch, start, length); 171 } 172 catch (ParseException pe) { 173 throw pe; 174 } 175 catch (Exception e) { 176 throw new ParseException(e, getLocator()); 177 } 178 } 179 180 /** 181 * Receive notification of the end of an element. 182 * 183 * <p>By default, do nothing. Application writers may override this 184 * method in a subclass to take specific actions at the end of 185 * each element (such as finalising a tree node or writing 186 * output to a file).</p> 187 * 188 * @param uri the URI. 189 * @param localName the element type name. 190 * @param qName the name. 191 * 192 * @exception SAXException Any SAX exception, possibly 193 * wrapping another exception. 194 * @see org.xml.sax.ContentHandler#endElement 195 */ 196 public void endElement(final String uri, final String localName, final String qName) 197 throws SAXException { 198 try { 199 peekFactory().endElement(qName); 200 } 201 catch (ParseException pe) { 202 throw pe; 203 } 204 catch (Exception e) { 205 throw new ParseException(e, getLocator()); 206 } 207 finally { 208 getCommentHandler().clearComments(); 209 } 210 } 211 212 213 /** 214 * Receive notification of the start of an element. 215 * 216 * <p>By default, do nothing. Application writers may override this 217 * method in a subclass to take specific actions at the start of 218 * each element (such as allocating a new tree node or writing 219 * output to a file).</p> 220 * 221 * @param uri the URI. 222 * @param localName the element type name. 223 * @param qName the name. 224 * @param attributes the specified or defaulted attributes. 225 * 226 * @exception SAXException Any SAX exception, possibly 227 * wrapping another exception. 228 * @see org.xml.sax.ContentHandler#startElement 229 */ 230 public void startElement(final String uri, final String localName, 231 final String qName, final Attributes attributes) 232 throws SAXException { 233 try { 234 peekFactory().startElement(qName, attributes); 235 } 236 catch (ParseException pe) { 237 throw pe; 238 } 239 catch (Exception e) { 240 throw new ParseException(e, getLocator()); 241 } 242 finally { 243 getCommentHandler().clearComments(); 244 } 245 } 246 247 /** 248 * Sets the initial handler. 249 * 250 * @param factory the initial handler. 251 */ 252 public void setInitialFactory(final ElementDefinitionHandler factory) { 253 this.initialFactory = factory; 254 } 255 256 /** 257 * Returns the initial handler. 258 * 259 * @return The initial handler. 260 */ 261 public ElementDefinitionHandler getInitialFactory() { 262 return this.initialFactory; 263 } 264 265 /** 266 * Sets a helper object. 267 * 268 * @param key the key. 269 * @param value the value. 270 */ 271 public void setHelperObject(final String key, final Object value) { 272 if (value == null) { 273 this.parserHelperObjects.remove(key); 274 } 275 else { 276 this.parserHelperObjects.put(key, value); 277 } 278 } 279 280 /** 281 * Returns a helper object. 282 * 283 * @param key the key. 284 * 285 * @return The object. 286 */ 287 public Object getHelperObject(final String key) { 288 return this.parserHelperObjects.get(key); 289 } 290 291 /** 292 * Returns a new instance of the parser. 293 * 294 * @return a new instance of the parser. 295 */ 296 public abstract Parser getInstance(); 297 298 /** 299 * Returns a new instance of {@link FrontendDefaultHandler}. 300 * 301 * @return A new instance. 302 */ 303 public final FrontendDefaultHandler newInstance() { 304 return getInstance(); 305 } 306 307 /** 308 * Returns the parsed result object after the parsing is complete. Calling 309 * this function during the parsing is undefined and may result in an 310 * IllegalStateException. 311 * 312 * @return the parsed result. 313 */ 314 public abstract Object getResult(); 315 }