2 Copyright (C) 1999,2000,2001 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 package gnu.xml.aelfred2;
40 import java.io.IOException;
41 import java.util.Locale;
44 import org.xml.sax.ext.*;
46 import gnu.xml.pipeline.EventFilter;
47 import gnu.xml.pipeline.ValidationConsumer;
51 * This SAX2 parser optionally layers a validator over the Ælfred2
52 * SAX2 parser. While this will not evaluate every XML validity constraint,
53 * it does support all the validity constraints that are of any real utility
54 * outside the strict SGML-compatible world. See the documentation for the
55 * SAXDriver class for information about the SAX2 features and properties
56 * that are supported, and documentation for the ValidationConsumer for
57 * information about what validity constraints may not be supported.
58 * (Ælfred2 tests some of those, even in non-validating mode, to
59 * achieve better conformance.)
61 * <p> Note that due to its internal construction, you can't change most
62 * handlers until parse() returns. This diverges slightly from SAX, which
63 * expects later binding to be supported. Early binding involves less
64 * runtime overhead, which is an issue for event pipelines as used inside
65 * this parser. Rather than relying on the parser to handle late binding
66 * to your own handlers, do it yourself.
69 * @see gnu.xml.pipeline.ValidationConsumer
71 * @author David Brownell
73 public final class XmlReader
77 static class FatalErrorHandler
78 extends DefaultHandler2
81 public void error(SAXParseException e)
89 private SAXDriver aelfred2 = new SAXDriver();
90 private EventFilter filter = new EventFilter();
91 private boolean isValidating;
92 private boolean active;
95 * Constructs a SAX Parser.
102 * Constructs a SAX Parser, optionally treating validity errors
103 * as if they were fatal errors.
105 public XmlReader(boolean invalidIsFatal)
109 setErrorHandler(new FatalErrorHandler());
114 * <b>SAX2</b>: Returns the object used to report the logical
115 * content of an XML document.
117 public ContentHandler getContentHandler()
119 return filter.getContentHandler();
123 * <b>SAX2</b>: Assigns the object used to report the logical
124 * content of an XML document.
125 * @exception IllegalStateException if called mid-parse
127 public void setContentHandler(ContentHandler handler)
131 throw new IllegalStateException("already parsing");
133 filter.setContentHandler(handler);
137 * <b>SAX2</b>: Returns the object used to process declarations related
138 * to notations and unparsed entities.
140 public DTDHandler getDTDHandler()
142 return filter.getDTDHandler();
146 * <b>SAX1</b> Assigns DTD handler
147 * @exception IllegalStateException if called mid-parse
149 public void setDTDHandler(DTDHandler handler)
153 throw new IllegalStateException("already parsing");
155 filter.setDTDHandler(handler);
159 * <b>SAX2</b>: Returns the object used when resolving external
160 * entities during parsing (both general and parameter entities).
162 public EntityResolver getEntityResolver()
164 return aelfred2.getEntityResolver();
168 * <b>SAX1</b> Assigns parser's entity resolver
170 public void setEntityResolver(EntityResolver handler)
172 aelfred2.setEntityResolver(handler);
176 * <b>SAX2</b>: Returns the object used to receive callbacks for XML
177 * errors of all levels (fatal, nonfatal, warning); this is never null;
179 public ErrorHandler getErrorHandler()
181 return aelfred2.getErrorHandler();
185 * <b>SAX1</b> Assigns error handler
186 * @exception IllegalStateException if called mid-parse
188 public void setErrorHandler(ErrorHandler handler)
192 throw new IllegalStateException("already parsing");
194 aelfred2.setErrorHandler(handler);
198 * <b>SAX2</b>: Assigns the specified property.
199 * @exception IllegalStateException if called mid-parse
201 public void setProperty(String propertyId, Object value)
202 throws SAXNotRecognizedException, SAXNotSupportedException
206 throw new IllegalStateException("already parsing");
208 if (getProperty(propertyId) != value)
210 filter.setProperty(propertyId, value);
215 * <b>SAX2</b>: Returns the specified property.
217 public Object getProperty(String propertyId)
218 throws SAXNotRecognizedException
220 if ((SAXDriver.PROPERTY + "declaration-handler").equals(propertyId)
221 || (SAXDriver.PROPERTY + "lexical-handler").equals(propertyId))
223 return filter.getProperty(propertyId);
225 throw new SAXNotRecognizedException(propertyId);
228 private void forceValidating()
229 throws SAXNotRecognizedException, SAXNotSupportedException
231 aelfred2.setFeature(SAXDriver.FEATURE + "namespace-prefixes",
233 aelfred2.setFeature(SAXDriver.FEATURE + "external-general-entities",
235 aelfred2.setFeature(SAXDriver.FEATURE + "external-parameter-entities",
240 * <b>SAX2</b>: Sets the state of features supported in this parser.
241 * Note that this parser requires reporting of namespace prefixes when
244 public void setFeature(String featureId, boolean state)
245 throws SAXNotRecognizedException, SAXNotSupportedException
247 boolean value = getFeature(featureId);
254 if ((SAXDriver.FEATURE + "validation").equals(featureId))
258 throw new SAXNotSupportedException("already parsing");
264 isValidating = state;
268 aelfred2.setFeature(featureId, state);
273 * <b>SAX2</b>: Tells whether this parser supports the specified feature.
274 * At this time, this directly parallels the underlying SAXDriver,
275 * except that validation is optionally supported.
279 public boolean getFeature(String featureId)
280 throws SAXNotRecognizedException, SAXNotSupportedException
282 if ((SAXDriver.FEATURE + "validation").equals(featureId))
287 return aelfred2.getFeature(featureId);
291 * <b>SAX1</b>: Sets the locale used for diagnostics; currently,
292 * only locales using the English language are supported.
293 * @param locale The locale for which diagnostics will be generated
295 public void setLocale(Locale locale)
298 aelfred2.setLocale(locale);
302 * <b>SAX1</b>: Preferred API to parse an XML document, using a
303 * system identifier (URI).
305 public void parse(String systemId)
306 throws SAXException, IOException
308 parse(new InputSource(systemId));
312 * <b>SAX1</b>: Underlying API to parse an XML document, used
313 * directly when no URI is available. When this is invoked,
314 * and the parser is set to validate, some features will be
315 * automatically reset to appropriate values: for reporting
316 * namespace prefixes, and incorporating external entities.
318 * @param source The XML input source.
320 * @exception IllegalStateException if called mid-parse
321 * @exception SAXException The handlers may throw any SAXException,
322 * and the parser normally throws SAXParseException objects.
323 * @exception IOException IOExceptions are normally through through
324 * the parser if there are problems reading the source document.
326 public void parse(InputSource source)
327 throws SAXException, IOException
332 synchronized (aelfred2)
336 throw new IllegalStateException("already parsing");
341 // set up the output pipeline
345 next = new ValidationConsumer(filter);
352 // connect pipeline and error handler
353 // don't let _this_ call to bind() affect xmlns* attributes
354 nsdecls = aelfred2.getFeature(SAXDriver.FEATURE + "namespace-prefixes");
355 EventFilter.bind(aelfred2, next);
358 aelfred2.setFeature(SAXDriver.FEATURE + "namespace-prefixes",
365 aelfred2.parse(source);