diff options
author | Brian Jones <cbj@gnu.org> | 2003-02-01 02:10:07 +0000 |
---|---|---|
committer | Brian Jones <cbj@gnu.org> | 2003-02-01 02:10:07 +0000 |
commit | a286d8e992bbc0a6180638df2bfb55e433642b78 (patch) | |
tree | 6c7ff3ab361b5543e219d49f537b2ecb38de6eb7 /external/jaxp/source/gnu/xml/aelfred2/SAXDriver.java | |
parent | a1314139baa4e9cd89051573d3bb5a5b556f3b32 (diff) | |
download | classpath-a286d8e992bbc0a6180638df2bfb55e433642b78.tar.gz |
Initial revision
Diffstat (limited to 'external/jaxp/source/gnu/xml/aelfred2/SAXDriver.java')
-rw-r--r-- | external/jaxp/source/gnu/xml/aelfred2/SAXDriver.java | 1271 |
1 files changed, 1271 insertions, 0 deletions
diff --git a/external/jaxp/source/gnu/xml/aelfred2/SAXDriver.java b/external/jaxp/source/gnu/xml/aelfred2/SAXDriver.java new file mode 100644 index 000000000..fc6d48a89 --- /dev/null +++ b/external/jaxp/source/gnu/xml/aelfred2/SAXDriver.java @@ -0,0 +1,1271 @@ +/* + * $Id: SAXDriver.java,v 1.1 2003-02-01 02:10:10 cbj Exp $ + * Copyright (C) 1999-2001 David Brownell + * + * This file is part of GNU JAXP, a library. + * + * GNU JAXP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GNU JAXP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * As a special exception, if you link this library with other files to + * produce an executable, this library does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * This exception does not however invalidate any other reasons why the + * executable file might be covered by the GNU General Public License. + */ + +// +// Copyright (c) 1998 by Microstar Software Ltd. +// From Microstar's README (the entire original license): +// +// Separate statements also said it's in the public domain. +// All modifications are distributed under the license +// above (GPL with library exception). +// +// AElfred is free for both commercial and non-commercial use and +// redistribution, provided that Microstar's copyright and disclaimer are +// retained intact. You are free to modify AElfred for your own use and +// to redistribute AElfred with your modifications, provided that the +// modifications are clearly documented. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// merchantability or fitness for a particular purpose. Please use it AT +// YOUR OWN RISK. +// + + +package gnu.xml.aelfred2; + +import java.io.*; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Locale; +import java.util.Stack; + +// maintaining 1.1 compatibility for now ... more portable, PJava, etc +// Iterator, Hashmap and ArrayList ought to be faster +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.xml.sax.*; +import org.xml.sax.ext.*; +import org.xml.sax.helpers.NamespaceSupport; + + +// $Id: SAXDriver.java,v 1.1 2003-02-01 02:10:10 cbj Exp $ + +/** + * An enhanced SAX2 version of Microstar's Ælfred XML parser. + * The enhancements primarily relate to significant improvements in + * conformance to the XML specification, and SAX2 support. Performance + * has been improved. See the package level documentation for more + * information. + * + * <table border="1" width='100%' cellpadding='3' cellspacing='0'> + * <tr bgcolor='#ccccff'> + * <th><font size='+1'>Name</font></th> + * <th><font size='+1'>Notes</font></th></tr> + * + * <tr><td colspan=2><center><em>Features ... URL prefix is + * <b>http://xml.org/sax/features/</b></em></center></td></tr> + * + * <tr><td>(URL)/external-general-entities</td> + * <td>Value defaults to <em>true</em></td></tr> + * <tr><td>(URL)/external-parameter-entities</td> + * <td>Value defaults to <em>true</em></td></tr> + * <tr><td>(URL)/is-standalone</td> + * <td>(PRELIMINARY) Returns true iff the document's parsing + * has started (some non-error event after <em>startDocument()</em> + * was reported) and the document's standalone flag is set.</td></tr> + * <tr><td>(URL)/namespace-prefixes</td> + * <td>Value defaults to <em>false</em> (but XML 1.0 names are + * always reported)</td></tr> + * <tr><td>(URL)/lexical-handler/parameter-entities</td> + * <td>Value is fixed at <em>true</em></td></tr> + * <tr><td>(URL)/namespaces</td> + * <td>Value defaults to <em>true</em></td></tr> + * <tr><td>(URL)/resolve-dtd-uris</td> + * <td>(PRELIMINARY) Value defaults to <em>true</em></td></tr> + * <tr><td>(URL)/string-interning</td> + * <td>Value is fixed at <em>true</em></td></tr> + * <tr><td>(URL)/use-attributes2</td> + * <td>(PRELIMINARY) Value is fixed at <em>true</em></td></tr> + * <tr><td>(URL)/use-entity-resolver2</td> + * <td>(PRELIMINARY) Value defaults to <em>true</em></td></tr> + * <tr><td>(URL)/validation</td> + * <td>Value is fixed at <em>false</em></td></tr> + * + * <tr><td colspan=2><center><em>Handler Properties ... URL prefix is + * <b>http://xml.org/sax/properties/</b></em></center></td></tr> + * + * <tr><td>(URL)/declaration-handler</td> + * <td>A declaration handler may be provided. </td></tr> + * <tr><td>(URL)/lexical-handler</td> + * <td>A lexical handler may be provided. </td></tr> + * </table> + * + * <p>This parser currently implements the SAX1 Parser API, but + * it may not continue to do so in the future. + * + * @author Written by David Megginson (version 1.2a from Microstar) + * @author Updated by David Brownell <dbrownell@users.sourceforge.net> + * @version $Date: 2003-02-01 02:10:10 $ + * @see org.xml.sax.Parser + */ +final public class SAXDriver + implements Locator, Attributes2, XMLReader, Parser, AttributeList +{ + private final DefaultHandler2 base = new DefaultHandler2 (); + private XmlParser parser; + + private EntityResolver entityResolver = base; + private EntityResolver2 resolver2 = null; + private ContentHandler contentHandler = base; + private DTDHandler dtdHandler = base; + private ErrorHandler errorHandler = base; + private DeclHandler declHandler = base; + private LexicalHandler lexicalHandler = base; + + private String elementName = null; + private Stack entityStack = new Stack (); + + // could use just one vector (of object/struct): faster, smaller + private Vector attributeNames = new Vector (); + private Vector attributeNamespaces = new Vector (); + private Vector attributeLocalNames = new Vector (); + private Vector attributeValues = new Vector (); + private boolean attributeSpecified [] = new boolean[10]; + private boolean attributeDeclared [] = new boolean[10]; + + private boolean namespaces = true; + private boolean xmlNames = false; + private boolean extGE = true; + private boolean extPE = true; + private boolean resolveAll = true; + private boolean useResolver2 = true; + + private int attributeCount = 0; + private boolean attributes; + private String nsTemp [] = new String [3]; + private NamespaceSupport prefixStack; + + // + // Constructor. + // + + /** Constructs a SAX Parser. */ + public SAXDriver () {} + + + // + // Implementation of org.xml.sax.Parser. + // + + /** + * <b>SAX1</b>: Sets the locale used for diagnostics; currently, + * only locales using the English language are supported. + * @param locale The locale for which diagnostics will be generated + */ + public void setLocale (Locale locale) + throws SAXException + { + if ("en".equals (locale.getLanguage ())) + return ; + + throw new SAXException ("AElfred2 only supports English locales."); + } + + + /** + * <b>SAX2</b>: Returns the object used when resolving external + * entities during parsing (both general and parameter entities). + */ + public EntityResolver getEntityResolver () + { + return (entityResolver == base) ? null : entityResolver; + } + + /** + * <b>SAX1, SAX2</b>: Set the entity resolver for this parser. + * @param handler The object to receive entity events. + */ + public void setEntityResolver (EntityResolver resolver) + { + if (resolver instanceof EntityResolver2) + resolver2 = (EntityResolver2) resolver; + else + resolver2 = null; + if (resolver == null) + resolver = base; + entityResolver = resolver; + } + + + /** + * <b>SAX2</b>: Returns the object used to process declarations related + * to notations and unparsed entities. + */ + public DTDHandler getDTDHandler () + { + return (dtdHandler == base) ? null : dtdHandler; + } + + /** + * <b>SAX1, SAX2</b>: Set the DTD handler for this parser. + * @param handler The object to receive DTD events. + */ + public void setDTDHandler (DTDHandler handler) + { + if (handler == null) + handler = base; + this.dtdHandler = handler; + } + + + /** + * <b>SAX1</b>: Set the document handler for this parser. If a + * content handler was set, this document handler will supplant it. + * The parser is set to report all XML 1.0 names rather than to + * filter out "xmlns" attributes (the "namespace-prefixes" feature + * is set to true). + * + * @deprecated SAX2 programs should use the XMLReader interface + * and a ContentHandler. + * + * @param handler The object to receive document events. + */ + public void setDocumentHandler (DocumentHandler handler) + { + contentHandler = new Adapter (handler); + xmlNames = true; + } + + /** + * <b>SAX2</b>: Returns the object used to report the logical + * content of an XML document. + */ + public ContentHandler getContentHandler () + { + return contentHandler == base ? null : contentHandler; + } + + /** + * <b>SAX2</b>: Assigns the object used to report the logical + * content of an XML document. If a document handler was set, + * this content handler will supplant it (but XML 1.0 style name + * reporting may remain enabled). + */ + public void setContentHandler (ContentHandler handler) + { + if (handler == null) + handler = base; + contentHandler = handler; + } + + /** + * <b>SAX1, SAX2</b>: Set the error handler for this parser. + * @param handler The object to receive error events. + */ + public void setErrorHandler (ErrorHandler handler) + { + if (handler == null) + handler = base; + this.errorHandler = handler; + } + + /** + * <b>SAX2</b>: Returns the object used to receive callbacks for XML + * errors of all levels (fatal, nonfatal, warning); this is never null; + */ + public ErrorHandler getErrorHandler () + { return errorHandler == base ? null : errorHandler; } + + + /** + * <b>SAX1, SAX2</b>: Auxiliary API to parse an XML document, used mostly + * when no URI is available. + * If you want anything useful to happen, you should set + * at least one type of handler. + * @param source The XML input source. Don't set 'encoding' unless + * you know for a fact that it's correct. + * @see #setEntityResolver + * @see #setDTDHandler + * @see #setContentHandler + * @see #setErrorHandler + * @exception SAXException The handlers may throw any SAXException, + * and the parser normally throws SAXParseException objects. + * @exception IOException IOExceptions are normally through through + * the parser if there are problems reading the source document. + */ + public void parse (InputSource source) + throws SAXException, IOException + { + synchronized (base) { + parser = new XmlParser (); + if (namespaces) + prefixStack = new NamespaceSupport (); + else if (!xmlNames) + throw new IllegalStateException (); + parser.setHandler (this); + + try { + + Reader r = source.getCharacterStream(); + InputStream in = source.getByteStream(); + + + parser.doParse (source.getSystemId (), + source.getPublicId (), + r, + in, + source.getEncoding ()); + } catch (SAXException e) { + throw e; + } catch (IOException e) { + throw e; + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new SAXParseException (e.getMessage (), this, e); + } finally { + contentHandler.endDocument (); + entityStack.removeAllElements (); + parser = null; + prefixStack = null; + } + } + } + + + /** + * <b>SAX1, SAX2</b>: Preferred API to parse an XML document, using a + * system identifier (URI). + */ + public void parse (String systemId) + throws SAXException, IOException + { + parse (new InputSource (systemId)); + } + + // + // Implementation of SAX2 "XMLReader" interface + // + static final String FEATURE = "http://xml.org/sax/features/"; + static final String PROPERTY = "http://xml.org/sax/properties/"; + + /** + * <b>SAX2</b>: Tells the value of the specified feature flag. + * + * @exception SAXNotRecognizedException thrown if the feature flag + * is neither built in, nor yet assigned. + */ + public boolean getFeature (String featureId) + throws SAXNotRecognizedException, SAXNotSupportedException + { + if ((FEATURE + "validation").equals (featureId)) + return false; + + // external entities (both types) are optionally included + if ((FEATURE + "external-general-entities").equals (featureId)) + return extGE; + if ((FEATURE + "external-parameter-entities") .equals (featureId)) + return extPE; + + // element/attribute names are as written in document; no mangling + if ((FEATURE + "namespace-prefixes").equals (featureId)) + return xmlNames; + + // report element/attribute namespaces? + if ((FEATURE + "namespaces").equals (featureId)) + return namespaces; + + // all PEs and GEs are reported + if ((FEATURE + "lexical-handler/parameter-entities").equals (featureId)) + return true; + + // always interns + if ((FEATURE + "string-interning").equals (featureId)) + return true; + + // EXTENSIONS 1.1 + + // always returns isSpecified info + if ((FEATURE + "use-attributes2").equals (featureId)) + return true; + + // meaningful between startDocument/endDocument + if ((FEATURE + "is-standalone").equals (featureId)) { + if (parser == null) + throw new SAXNotSupportedException (featureId); + return parser.isStandalone (); + } + + // optionally don't absolutize URIs in declarations + if ((FEATURE + "resolve-dtd-uris").equals (featureId)) + return resolveAll; + + // optionally use resolver2 interface methods, if possible + if ((FEATURE + "use-entity-resolver2").equals (featureId)) + return useResolver2; + + throw new SAXNotRecognizedException (featureId); + } + + // package private + DeclHandler getDeclHandler () { return declHandler; } + + // package private + boolean resolveURIs () { return resolveAll; } + + /** + * <b>SAX2</b>: Returns the specified property. + * + * @exception SAXNotRecognizedException thrown if the property value + * is neither built in, nor yet stored. + */ + public Object getProperty (String propertyId) + throws SAXNotRecognizedException + { + if ((PROPERTY + "declaration-handler").equals (propertyId)) + return declHandler == base ? null : declHandler; + + if ((PROPERTY + "lexical-handler").equals (propertyId)) + return lexicalHandler == base ? null : lexicalHandler; + + // unknown properties + throw new SAXNotRecognizedException (propertyId); + } + + /** + * <b>SAX2</b>: Sets the state of feature flags in this parser. Some + * built-in feature flags are mutable. + */ + public void setFeature (String featureId, boolean value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + boolean state; + + // Features with a defined value, we just change it if we can. + state = getFeature (featureId); + + if (state == value) + return; + if (parser != null) + throw new SAXNotSupportedException ("not while parsing"); + + if ((FEATURE + "namespace-prefixes").equals (featureId)) { + // in this implementation, this only affects xmlns reporting + xmlNames = value; + // forcibly prevent illegal parser state + if (!xmlNames) + namespaces = true; + return; + } + + if ((FEATURE + "namespaces").equals (featureId)) { + namespaces = value; + // forcibly prevent illegal parser state + if (!namespaces) + xmlNames = true; + return; + } + + if ((FEATURE + "external-general-entities").equals (featureId)) { + extGE = value; + return; + } + if ((FEATURE + "external-parameter-entities") .equals (featureId)) { + extPE = value; + return; + } + if ((FEATURE + "resolve-dtd-uris").equals (featureId)) { + resolveAll = value; + return; + } + + if ((FEATURE + "use-entity-resolver2").equals (featureId)) { + useResolver2 = value; + return; + } + + throw new SAXNotRecognizedException (featureId); + } + + /** + * <b>SAX2</b>: Assigns the specified property. Like SAX1 handlers, + * these may be changed at any time. + */ + public void setProperty (String propertyId, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + // see if the property is recognized + getProperty (propertyId); + + // Properties with a defined value, we just change it if we can. + + if ((PROPERTY + "declaration-handler").equals (propertyId)) { + if (value == null) + declHandler = base; + else if (! (value instanceof DeclHandler)) + throw new SAXNotSupportedException (propertyId); + else + declHandler = (DeclHandler) value; + return ; + } + + if ((PROPERTY + "lexical-handler").equals (propertyId)) { + if (value == null) + lexicalHandler = base; + else if (! (value instanceof LexicalHandler)) + throw new SAXNotSupportedException (propertyId); + else + lexicalHandler = (LexicalHandler) value; + return ; + } + + throw new SAXNotSupportedException (propertyId); + } + + + // + // This is where the driver receives XmlParser callbacks and translates + // them into SAX callbacks. Some more callbacks have been added for + // SAX2 support. + // + + void startDocument () + throws SAXException + { + contentHandler.setDocumentLocator (this); + contentHandler.startDocument (); + attributeNames.removeAllElements (); + attributeValues.removeAllElements (); + } + + void skippedEntity (String name) + throws SAXException + { contentHandler.skippedEntity (name); } + + InputSource getExternalSubset (String name, String baseURI) + throws SAXException, IOException + { + if (resolver2 == null || !useResolver2 || !extPE) + return null; + return resolver2.getExternalSubset (name, baseURI); + } + + InputSource resolveEntity (boolean isPE, String name, + InputSource in, String baseURI) + throws SAXException, IOException + { + InputSource source; + + // external entities might be skipped + if (isPE && !extPE) + return null; + if (!isPE && !extGE) + return null; + + // ... or not + lexicalHandler.startEntity (name); + if (resolver2 != null && useResolver2) { + source = resolver2.resolveEntity (name, in.getPublicId (), + baseURI, in.getSystemId ()); + if (source == null) { + in.setSystemId (absolutize (baseURI, + in.getSystemId (), false)); + source = in; + } + } else { + in.setSystemId (absolutize (baseURI, in.getSystemId (), false)); + source = entityResolver.resolveEntity (in.getPublicId (), + in.getSystemId ()); + if (source == null) + source = in; + } + startExternalEntity (name, source.getSystemId (), true); + return source; + } + + // absolutize a system ID relative to the specified base URI + // (temporarily) package-visible for external entity decls + String absolutize (String baseURI, String systemId, boolean nice) + throws MalformedURLException, SAXException + { + // FIXME normalize system IDs -- when? + // - Convert to UTF-8 + // - Map reserved and non-ASCII characters to %HH + + try { + if (baseURI == null) { + warn ("No base URI; hope this SYSTEM id is absolute: " + + systemId); + return new URL (systemId).toString (); + } else + return new URL (new URL (baseURI), systemId).toString (); + + } catch (MalformedURLException e) { + + // Let unknown URI schemes pass through unless we need + // the JVM to map them to i/o streams for us... + if (!nice) + throw e; + + // sometimes sysids for notations or unparsed entities + // aren't really URIs... + warn ("Can't absolutize SYSTEM id: " + e.getMessage ()); + return systemId; + } + } + + void startExternalEntity (String name, String systemId, + boolean stackOnly) + throws SAXException + { + if (systemId == null) + warn ("URI was not reported to parser for entity " + name); + if (!stackOnly) // spliced [dtd] needs startEntity + lexicalHandler.startEntity (name); + entityStack.push (systemId); + } + + void endExternalEntity (String name) + throws SAXException + { + if (!"[document]".equals (name)) + lexicalHandler.endEntity (name); + entityStack.pop (); + } + + void startInternalEntity (String name) + throws SAXException + { + lexicalHandler.startEntity (name); + } + + void endInternalEntity (String name) + throws SAXException + { + lexicalHandler.endEntity (name); + } + + void doctypeDecl (String name, String publicId, String systemId) + throws SAXException + { + lexicalHandler.startDTD (name, publicId, systemId); + + // ... the "name" is a declaration and should be given + // to the DeclHandler (but sax2 doesn't). + + // the IDs for the external subset are lexical details, + // as are the contents of the internal subset; but sax2 + // doesn't provide the internal subset "pre-parse" + } + + void notationDecl (String name, String ids []) + throws SAXException + { + try { + dtdHandler.notationDecl (name, ids [0], + (resolveAll && ids [1] != null) + ? absolutize (ids [2], ids [1], true) + : ids [1]); + } catch (IOException e) { + // "can't happen" + throw new SAXParseException (e.getMessage (), this, e); + } + } + + void unparsedEntityDecl (String name, String ids [], String notation) + throws SAXException + { + try { + dtdHandler.unparsedEntityDecl (name, ids [0], + resolveAll + ? absolutize (ids [2], ids [1], true) + : ids [1], + notation); + } catch (IOException e) { + // "can't happen" + throw new SAXParseException (e.getMessage (), this, e); + } + } + + void endDoctype () + throws SAXException + { + lexicalHandler.endDTD (); + } + + private void declarePrefix (String prefix, String uri) + throws SAXException + { + int index = uri.indexOf (':'); + + // many versions of nwalsh docbook stylesheets + // have bogus URLs; so this can't be an error... + if (index < 1 && uri.length () != 0) + warn ("relative URI for namespace: " + uri); + + // FIXME: char [0] must be ascii alpha; chars [1..index] + // must be ascii alphanumeric or in "+-." [RFC 2396] + + uri = uri.intern (); + prefixStack.declarePrefix (prefix, uri); + contentHandler.startPrefixMapping (prefix, uri); + } + + void attribute (String qname, String value, boolean isSpecified) + throws SAXException + { + if (!attributes) { + attributes = true; + if (namespaces) + prefixStack.pushContext (); + } + + // process namespace decls immediately; + // then maybe forget this as an attribute + if (namespaces) { + int index; + + // default NS declaration? + if ("xmlns" == qname) { + declarePrefix ("", value); + if (!xmlNames) + return; + } + + // NS prefix declaration? + else if ((index = qname.indexOf (':')) == 5 + && qname.startsWith ("xmlns")) { + String prefix = qname.substring (6); + + if (value.length () == 0) { + verror ("missing URI in namespace decl attribute: " + + qname); + } else + declarePrefix (prefix, value); + if (!xmlNames) + return; + } + } + + // remember this attribute ... + + if (attributeCount == attributeSpecified.length) { // grow array? + boolean temp [] = new boolean [attributeSpecified.length + 5]; + System.arraycopy (attributeSpecified, 0, temp, 0, attributeCount); + attributeSpecified = temp; + } + attributeSpecified [attributeCount] = isSpecified; + + attributeCount++; + attributeNames.addElement (qname); + // attribute type comes from querying parser's DTD records + attributeValues.addElement (value); + + // ... patching {lname, uri} later, if needed + attributeNamespaces.addElement (""); + attributeLocalNames.addElement (""); + } + + void startElement (String elname) + throws SAXException + { + ContentHandler handler = contentHandler; + + // + // NOTE: this implementation of namespace support adds something + // like six percent to parsing CPU time, in a large (~50 MB) + // document that doesn't use namespaces at all. (Measured by PC + // sampling, with a bug where endElement processing was omitted.) + // [Measurement referred to older implementation, older JVM ...] + // + // It ought to become notably faster in such cases. Most + // costs are the prefix stack calling Hashtable.get() (2%), + // String.hashCode() (1.5%) and about 1.3% each for pushing + // the context, and two chunks of name processing. + // + + if (!attributes) { + if (namespaces) + prefixStack.pushContext (); + } else if (namespaces) { + + // now we can patch up namespace refs; we saw all the + // declarations, so now we'll do the Right Thing + for (int i = 0; i < attributeCount; i++) { + String qname = (String) attributeNames.elementAt (i); + int index; + + // default NS declaration? + if ("xmlns" == qname) + continue; + + index = qname.indexOf (':'); + + // NS prefix declaration? + if (index == 5 && qname.startsWith ("xmlns")) + continue; + + // it's not a NS decl; patch namespace info items + if (prefixStack.processName (qname, nsTemp, true) == null) + verror ("undeclared attribute prefix in: " + qname); + else { + attributeNamespaces.setElementAt (nsTemp [0], i); + attributeLocalNames.setElementAt (nsTemp [1], i); + } + } + } + + // save element name so attribute callbacks work + elementName = elname; + if (namespaces) { + if (prefixStack.processName (elname, nsTemp, false) == null) { + verror ("undeclared element prefix in: " + elname); + nsTemp [0] = nsTemp [1] = ""; + } + handler.startElement (nsTemp [0], nsTemp [1], elname, this); + } else + handler.startElement ("", "", elname, this); + // elementName = null; + + // elements with no attributes are pretty common! + if (attributes) { + attributeNames.removeAllElements (); + attributeNamespaces.removeAllElements (); + attributeLocalNames.removeAllElements (); + attributeValues.removeAllElements (); + attributeCount = 0; + attributes = false; + } + } + + void endElement (String elname) + throws SAXException + { + ContentHandler handler = contentHandler; + + if (!namespaces) { + handler.endElement ("", "", elname); + return; + } + prefixStack.processName (elname, nsTemp, false); + handler.endElement (nsTemp [0], nsTemp [1], elname); + + Enumeration prefixes = prefixStack.getDeclaredPrefixes (); + + while (prefixes.hasMoreElements ()) + handler.endPrefixMapping ((String) prefixes.nextElement ()); + prefixStack.popContext (); + } + + void startCDATA () + throws SAXException + { + lexicalHandler.startCDATA (); + } + + void charData (char ch[], int start, int length) + throws SAXException + { + contentHandler.characters (ch, start, length); + } + + void endCDATA () + throws SAXException + { + lexicalHandler.endCDATA (); + } + + void ignorableWhitespace (char ch[], int start, int length) + throws SAXException + { + contentHandler.ignorableWhitespace (ch, start, length); + } + + void processingInstruction (String target, String data) + throws SAXException + { + contentHandler.processingInstruction (target, data); + } + + void comment (char ch[], int start, int length) + throws SAXException + { + if (lexicalHandler != base) + lexicalHandler.comment (ch, start, length); + } + + void fatal (String message) + throws SAXException + { + SAXParseException fatal; + + fatal = new SAXParseException (message, this); + errorHandler.fatalError (fatal); + + // Even if the application can continue ... we can't! + throw fatal; + } + + // We can safely report a few validity errors that + // make layered SAX2 DTD validation more conformant + void verror (String message) + throws SAXException + { + SAXParseException err; + + err = new SAXParseException (message, this); + errorHandler.error (err); + } + + void warn (String message) + throws SAXException + { + SAXParseException err; + + err = new SAXParseException (message, this); + errorHandler.warning (err); + } + + + // + // Implementation of org.xml.sax.Attributes. + // + + /** + * <b>SAX1 AttributeList, SAX2 Attributes</b> method + * (don't invoke on parser); + */ + public int getLength () + { + return attributeNames.size (); + } + + /** + * <b>SAX2 Attributes</b> method (don't invoke on parser); + */ + public String getURI (int index) + { + return (String) (attributeNamespaces.elementAt (index)); + } + + /** + * <b>SAX2 Attributes</b> method (don't invoke on parser); + */ + public String getLocalName (int index) + { + return (String) (attributeLocalNames.elementAt (index)); + } + + /** + * <b>SAX2 Attributes</b> method (don't invoke on parser); + */ + public String getQName (int i) + { + return (String) (attributeNames.elementAt (i)); + } + + /** + * <b>SAX1 AttributeList</b> method (don't invoke on parser); + */ + public String getName (int i) + { + return (String) (attributeNames.elementAt (i)); + } + + /** + * <b>SAX1 AttributeList, SAX2 Attributes</b> method + * (don't invoke on parser); + */ + public String getType (int i) + { + String type = parser.getAttributeType (elementName, getQName (i)); + if (type == null) + return "CDATA"; + // ... use DeclHandler.attributeDecl to see enumerations + if (type == "ENUMERATION") + return "NMTOKEN"; + return type; + } + + + /** + * <b>SAX1 AttributeList, SAX2 Attributes</b> method + * (don't invoke on parser); + */ + public String getValue (int i) + { + return (String) (attributeValues.elementAt (i)); + } + + + /** + * <b>SAX2 Attributes</b> method (don't invoke on parser); + */ + public int getIndex (String uri, String local) + { + int length = getLength (); + + for (int i = 0; i < length; i++) { + if (!getURI (i).equals (uri)) + continue; + if (getLocalName (i).equals (local)) + return i; + } + return -1; + } + + + /** + * <b>SAX2 Attributes</b> method (don't invoke on parser); + */ + public int getIndex (String xmlName) + { + int length = getLength (); + + for (int i = 0; i < length; i++) { + if (getQName (i).equals (xmlName)) + return i; + } + return -1; + } + + + /** + * <b>SAX2 Attributes</b> method (don't invoke on parser); + */ + public String getType (String uri, String local) + { + int index = getIndex (uri, local); + + if (index < 0) + return null; + return getType (index); + } + + + /** + * <b>SAX1 AttributeList, SAX2 Attributes</b> method + * (don't invoke on parser); + */ + public String getType (String xmlName) + { + int index = getIndex (xmlName); + + if (index < 0) + return null; + return getType (index); + } + + + /** + * <b>SAX Attributes</b> method (don't invoke on parser); + */ + public String getValue (String uri, String local) + { + int index = getIndex (uri, local); + + if (index < 0) + return null; + return getValue (index); + } + + + /** + * <b>SAX1 AttributeList, SAX2 Attributes</b> method + * (don't invoke on parser); + */ + public String getValue (String xmlName) + { + int index = getIndex (xmlName); + + if (index < 0) + return null; + return getValue (index); + } + + + // + // Implementation of org.xml.sax.ext.Attributes2 + // + + + /** @return false unless the attribute was declared in the DTD. + * @throws java.lang.ArrayIndexOutOfBoundsException + * When the supplied index does not identify an attribute. + */ + public boolean isDeclared (int index) + { + if (index < 0 || index >= attributeCount) + throw new ArrayIndexOutOfBoundsException (); + return attributeDeclared [index]; + } + + /** @return false unless the attribute was declared in the DTD. + * @throws java.lang.IllegalArgumentException + * When the supplied names do not identify an attribute. + */ + public boolean isDeclared (java.lang.String qName) + { + int index = getIndex (qName); + if (index < 0) + throw new IllegalArgumentException (); + return attributeDeclared [index]; + } + + /** @return false unless the attribute was declared in the DTD. + * @throws java.lang.IllegalArgumentException + * When the supplied names do not identify an attribute. + */ + public boolean isDeclared (java.lang.String uri, java.lang.String localName) + { + int index = getIndex (uri, localName); + if (index < 0) + throw new IllegalArgumentException (); + return attributeDeclared [index]; + } + + + /** + * <b>SAX-ext Attributes2</b> method (don't invoke on parser); + */ + public boolean isSpecified (int index) + { + if (index < 0 || index >= attributeCount) + throw new ArrayIndexOutOfBoundsException (); + return attributeSpecified [index]; + } + + /** + * <b>SAX-ext Attributes2</b> method (don't invoke on parser); + */ + public boolean isSpecified (String uri, String local) + { + int index = getIndex (uri, local); + + if (index < 0) + throw new IllegalArgumentException (); + return attributeSpecified [index]; + } + + /** + * <b>SAX-ext Attributes2</b> method (don't invoke on parser); + */ + public boolean isSpecified (String xmlName) + { + int index = getIndex (xmlName); + + if (index < 0) + throw new IllegalArgumentException (); + return attributeSpecified [index]; + } + + + // + // Implementation of org.xml.sax.Locator. + // + + /** + * <b>SAX Locator</b> method (don't invoke on parser); + */ + public String getPublicId () + { + return null; // FIXME track public IDs too + } + + /** + * <b>SAX Locator</b> method (don't invoke on parser); + */ + public String getSystemId () + { + if (entityStack.empty ()) + return null; + else + return (String) entityStack.peek (); + } + + /** + * <b>SAX Locator</b> method (don't invoke on parser); + */ + public int getLineNumber () + { + return parser.getLineNumber (); + } + + /** + * <b>SAX Locator</b> method (don't invoke on parser); + */ + public int getColumnNumber () + { + return parser.getColumnNumber (); + } + + // adapter between SAX2 content handler and SAX1 document handler callbacks + private static class Adapter implements ContentHandler + { + private DocumentHandler docHandler; + + Adapter (DocumentHandler dh) + { docHandler = dh; } + + + public void setDocumentLocator (Locator l) + { docHandler.setDocumentLocator (l); } + + public void startDocument () throws SAXException + { docHandler.startDocument (); } + + public void processingInstruction (String target, String data) + throws SAXException + { docHandler.processingInstruction (target, data); } + + public void startPrefixMapping (String prefix, String uri) + { /* ignored */ } + + public void startElement ( + String namespace, + String local, + String name, + Attributes attrs + ) throws SAXException + { docHandler.startElement (name, (AttributeList) attrs); } + + public void characters (char buf [], int offset, int len) + throws SAXException + { docHandler.characters (buf, offset, len); } + + public void ignorableWhitespace (char buf [], int offset, int len) + throws SAXException + { docHandler.ignorableWhitespace (buf, offset, len); } + + public void skippedEntity (String name) + { /* ignored */ } + + public void endElement (String u, String l, String name) + throws SAXException + { docHandler.endElement (name); } + + public void endPrefixMapping (String prefix) + { /* ignored */ } + + public void endDocument () throws SAXException + { docHandler.endDocument (); } + } +} |