2 Copyright (C) 1999,2000,2001,2004 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 Portions derived from code which carried the following notice:
40 Copyright (c) 1997, 1998 by Microstar Software Ltd.
42 AElfred is free for both commercial and non-commercial use and
43 redistribution, provided that Microstar's copyright and disclaimer are
44 retained intact. You are free to modify AElfred for your own use and
45 to redistribute AElfred with your modifications, provided that the
46 modifications are clearly documented.
48 This program is distributed in the hope that it will be useful, but
49 WITHOUT ANY WARRANTY; without even the implied warranty of
50 merchantability or fitness for a particular purpose. Please use it AT
54 package gnu
.xml
.aelfred2
;
58 import java
.net
.MalformedURLException
;
60 import java
.util
.Locale
;
61 import java
.util
.Stack
;
63 // maintaining 1.1 compatibility for now ... more portable, PJava, etc
64 // Iterator, Hashmap and ArrayList ought to be faster
65 import java
.util
.ArrayList
;
66 import java
.util
.Collections
;
67 import java
.util
.Enumeration
;
68 import java
.util
.Hashtable
;
69 import java
.util
.Iterator
;
70 import java
.util
.List
;
71 import java
.util
.Vector
;
74 import org
.xml
.sax
.ext
.*;
75 import org
.xml
.sax
.helpers
.NamespaceSupport
;
79 * An enhanced SAX2 version of Microstar's Ælfred XML parser.
80 * The enhancements primarily relate to significant improvements in
81 * conformance to the XML specification, and SAX2 support. Performance
82 * has been improved. See the package level documentation for more
85 * <table border="1" width='100%' cellpadding='3' cellspacing='0'>
86 * <tr bgcolor='#ccccff'>
87 * <th><font size='+1'>Name</font></th>
88 * <th><font size='+1'>Notes</font></th></tr>
90 * <tr><td colspan=2><center><em>Features ... URL prefix is
91 * <b>http://xml.org/sax/features/</b></em></center></td></tr>
93 * <tr><td>(URL)/external-general-entities</td>
94 * <td>Value defaults to <em>true</em></td></tr>
95 * <tr><td>(URL)/external-parameter-entities</td>
96 * <td>Value defaults to <em>true</em></td></tr>
97 * <tr><td>(URL)/is-standalone</td>
98 * <td>(PRELIMINARY) Returns true iff the document's parsing
99 * has started (some non-error event after <em>startDocument()</em>
100 * was reported) and the document's standalone flag is set.</td></tr>
101 * <tr><td>(URL)/namespace-prefixes</td>
102 * <td>Value defaults to <em>false</em> (but XML 1.0 names are
103 * always reported)</td></tr>
104 * <tr><td>(URL)/lexical-handler/parameter-entities</td>
105 * <td>Value is fixed at <em>true</em></td></tr>
106 * <tr><td>(URL)/namespaces</td>
107 * <td>Value defaults to <em>true</em></td></tr>
108 * <tr><td>(URL)/resolve-dtd-uris</td>
109 * <td>(PRELIMINARY) Value defaults to <em>true</em></td></tr>
110 * <tr><td>(URL)/string-interning</td>
111 * <td>Value is fixed at <em>true</em></td></tr>
112 * <tr><td>(URL)/use-attributes2</td>
113 * <td>(PRELIMINARY) Value is fixed at <em>true</em></td></tr>
114 * <tr><td>(URL)/use-entity-resolver2</td>
115 * <td>(PRELIMINARY) Value defaults to <em>true</em></td></tr>
116 * <tr><td>(URL)/validation</td>
117 * <td>Value is fixed at <em>false</em></td></tr>
119 * <tr><td colspan=2><center><em>Handler Properties ... URL prefix is
120 * <b>http://xml.org/sax/properties/</b></em></center></td></tr>
122 * <tr><td>(URL)/declaration-handler</td>
123 * <td>A declaration handler may be provided. </td></tr>
124 * <tr><td>(URL)/lexical-handler</td>
125 * <td>A lexical handler may be provided. </td></tr>
128 * <p>This parser currently implements the SAX1 Parser API, but
129 * it may not continue to do so in the future.
131 * @author Written by David Megginson (version 1.2a from Microstar)
132 * @author Updated by David Brownell <dbrownell@users.sourceforge.net>
133 * @see org.xml.sax.Parser
135 final public class SAXDriver
136 implements Locator
, Attributes2
, XMLReader
, Parser
, AttributeList
138 private final DefaultHandler2 base
= new DefaultHandler2 ();
139 private XmlParser parser
;
141 private EntityResolver entityResolver
= base
;
142 private EntityResolver2 resolver2
= null;
143 private ContentHandler contentHandler
= base
;
144 private DTDHandler dtdHandler
= base
;
145 private ErrorHandler errorHandler
= base
;
146 private DeclHandler declHandler
= base
;
147 private LexicalHandler lexicalHandler
= base
;
149 private String elementName
;
150 private Stack entityStack
;
152 // one vector (of object/struct): faster, smaller
153 private List attributesList
;
155 private boolean namespaces
= true;
156 private boolean xmlNames
= false;
157 private boolean extGE
= true;
158 private boolean extPE
= true;
159 private boolean resolveAll
= true;
160 private boolean useResolver2
= true;
161 private boolean stringInterning
= true;
163 private int attributeCount
;
164 private boolean attributes
;
165 private String nsTemp
[];
166 private NamespaceSupport prefixStack
;
172 /** Constructs a SAX Parser. */
178 private void reset ()
181 entityStack
= new Stack ();
182 attributesList
= Collections
.synchronizedList(new ArrayList());
185 nsTemp
= new String
[3];
191 // Implementation of org.xml.sax.Parser.
195 * <b>SAX1</b>: Sets the locale used for diagnostics; currently,
196 * only locales using the English language are supported.
197 * @param locale The locale for which diagnostics will be generated
199 public void setLocale (Locale locale
)
202 if ("en".equals (locale
.getLanguage ()))
205 throw new SAXException ("AElfred2 only supports English locales.");
210 * <b>SAX2</b>: Returns the object used when resolving external
211 * entities during parsing (both general and parameter entities).
213 public EntityResolver
getEntityResolver ()
215 return (entityResolver
== base
) ?
null : entityResolver
;
219 * <b>SAX1, SAX2</b>: Set the entity resolver for this parser.
220 * @param handler The object to receive entity events.
222 public void setEntityResolver (EntityResolver resolver
)
224 if (resolver
instanceof EntityResolver2
)
225 resolver2
= (EntityResolver2
) resolver
;
228 if (resolver
== null)
230 entityResolver
= resolver
;
235 * <b>SAX2</b>: Returns the object used to process declarations related
236 * to notations and unparsed entities.
238 public DTDHandler
getDTDHandler ()
240 return (dtdHandler
== base
) ?
null : dtdHandler
;
244 * <b>SAX1, SAX2</b>: Set the DTD handler for this parser.
245 * @param handler The object to receive DTD events.
247 public void setDTDHandler (DTDHandler handler
)
251 this.dtdHandler
= handler
;
256 * <b>SAX1</b>: Set the document handler for this parser. If a
257 * content handler was set, this document handler will supplant it.
258 * The parser is set to report all XML 1.0 names rather than to
259 * filter out "xmlns" attributes (the "namespace-prefixes" feature
262 * @deprecated SAX2 programs should use the XMLReader interface
263 * and a ContentHandler.
265 * @param handler The object to receive document events.
267 public void setDocumentHandler (DocumentHandler handler
)
269 contentHandler
= new Adapter (handler
);
274 * <b>SAX2</b>: Returns the object used to report the logical
275 * content of an XML document.
277 public ContentHandler
getContentHandler ()
279 return contentHandler
== base ?
null : contentHandler
;
283 * <b>SAX2</b>: Assigns the object used to report the logical
284 * content of an XML document. If a document handler was set,
285 * this content handler will supplant it (but XML 1.0 style name
286 * reporting may remain enabled).
288 public void setContentHandler (ContentHandler handler
)
292 contentHandler
= handler
;
296 * <b>SAX1, SAX2</b>: Set the error handler for this parser.
297 * @param handler The object to receive error events.
299 public void setErrorHandler (ErrorHandler handler
)
303 this.errorHandler
= handler
;
307 * <b>SAX2</b>: Returns the object used to receive callbacks for XML
308 * errors of all levels (fatal, nonfatal, warning); this is never null;
310 public ErrorHandler
getErrorHandler ()
311 { return errorHandler
== base ?
null : errorHandler
; }
315 * <b>SAX1, SAX2</b>: Auxiliary API to parse an XML document, used mostly
316 * when no URI is available.
317 * If you want anything useful to happen, you should set
318 * at least one type of handler.
319 * @param source The XML input source. Don't set 'encoding' unless
320 * you know for a fact that it's correct.
321 * @see #setEntityResolver
322 * @see #setDTDHandler
323 * @see #setContentHandler
324 * @see #setErrorHandler
325 * @exception SAXException The handlers may throw any SAXException,
326 * and the parser normally throws SAXParseException objects.
327 * @exception IOException IOExceptions are normally through through
328 * the parser if there are problems reading the source document.
330 public void parse (InputSource source
)
331 throws SAXException
, IOException
333 synchronized (base
) {
334 parser
= new XmlParser ();
336 prefixStack
= new NamespaceSupport ();
338 throw new IllegalStateException ();
339 parser
.setHandler (this);
343 Reader r
= source
.getCharacterStream();
344 InputStream in
= source
.getByteStream();
347 parser
.doParse (source
.getSystemId (),
348 source
.getPublicId (),
351 source
.getEncoding ());
352 } catch (SAXException e
) {
354 } catch (IOException e
) {
356 } catch (RuntimeException e
) {
358 } catch (Exception e
) {
359 throw new SAXParseException (e
.getMessage (), this, e
);
361 contentHandler
.endDocument ();
369 * <b>SAX1, SAX2</b>: Preferred API to parse an XML document, using a
370 * system identifier (URI).
372 public void parse (String systemId
)
373 throws SAXException
, IOException
375 parse (new InputSource (systemId
));
379 // Implementation of SAX2 "XMLReader" interface
381 static final String FEATURE
= "http://xml.org/sax/features/";
382 static final String PROPERTY
= "http://xml.org/sax/properties/";
385 * <b>SAX2</b>: Tells the value of the specified feature flag.
387 * @exception SAXNotRecognizedException thrown if the feature flag
388 * is neither built in, nor yet assigned.
390 public boolean getFeature (String featureId
)
391 throws SAXNotRecognizedException
, SAXNotSupportedException
393 if ((FEATURE
+ "validation").equals (featureId
))
396 // external entities (both types) are optionally included
397 if ((FEATURE
+ "external-general-entities").equals (featureId
))
399 if ((FEATURE
+ "external-parameter-entities") .equals (featureId
))
402 // element/attribute names are as written in document; no mangling
403 if ((FEATURE
+ "namespace-prefixes").equals (featureId
))
406 // report element/attribute namespaces?
407 if ((FEATURE
+ "namespaces").equals (featureId
))
410 // all PEs and GEs are reported
411 if ((FEATURE
+ "lexical-handler/parameter-entities").equals (featureId
))
415 if ((FEATURE
+ "string-interning").equals (featureId
))
416 return stringInterning
;
420 // always returns isSpecified info
421 if ((FEATURE
+ "use-attributes2").equals (featureId
))
424 // meaningful between startDocument/endDocument
425 if ((FEATURE
+ "is-standalone").equals (featureId
)) {
427 throw new SAXNotSupportedException (featureId
);
428 return parser
.isStandalone ();
431 // optionally don't absolutize URIs in declarations
432 if ((FEATURE
+ "resolve-dtd-uris").equals (featureId
))
435 // optionally use resolver2 interface methods, if possible
436 if ((FEATURE
+ "use-entity-resolver2").equals (featureId
))
439 throw new SAXNotRecognizedException (featureId
);
443 DeclHandler
getDeclHandler () { return declHandler
; }
446 boolean resolveURIs () { return resolveAll
; }
449 * <b>SAX2</b>: Returns the specified property.
451 * @exception SAXNotRecognizedException thrown if the property value
452 * is neither built in, nor yet stored.
454 public Object
getProperty (String propertyId
)
455 throws SAXNotRecognizedException
457 if ((PROPERTY
+ "declaration-handler").equals (propertyId
))
458 return declHandler
== base ?
null : declHandler
;
460 if ((PROPERTY
+ "lexical-handler").equals (propertyId
))
461 return lexicalHandler
== base ?
null : lexicalHandler
;
463 // unknown properties
464 throw new SAXNotRecognizedException (propertyId
);
468 * <b>SAX2</b>: Sets the state of feature flags in this parser. Some
469 * built-in feature flags are mutable.
471 public void setFeature (String featureId
, boolean value
)
472 throws SAXNotRecognizedException
, SAXNotSupportedException
476 // Features with a defined value, we just change it if we can.
477 state
= getFeature (featureId
);
482 throw new SAXNotSupportedException ("not while parsing");
484 if ((FEATURE
+ "namespace-prefixes").equals (featureId
)) {
485 // in this implementation, this only affects xmlns reporting
487 // forcibly prevent illegal parser state
493 if ((FEATURE
+ "namespaces").equals (featureId
)) {
495 // forcibly prevent illegal parser state
501 if ((FEATURE
+ "external-general-entities").equals (featureId
)) {
505 if ((FEATURE
+ "external-parameter-entities") .equals (featureId
)) {
509 if ((FEATURE
+ "resolve-dtd-uris").equals (featureId
)) {
514 if ((FEATURE
+ "use-entity-resolver2").equals (featureId
)) {
515 useResolver2
= value
;
519 throw new SAXNotRecognizedException (featureId
);
523 * <b>SAX2</b>: Assigns the specified property. Like SAX1 handlers,
524 * these may be changed at any time.
526 public void setProperty (String propertyId
, Object value
)
527 throws SAXNotRecognizedException
, SAXNotSupportedException
529 // see if the property is recognized
530 getProperty (propertyId
);
532 // Properties with a defined value, we just change it if we can.
534 if ((PROPERTY
+ "declaration-handler").equals (propertyId
)) {
537 else if (! (value
instanceof DeclHandler
))
538 throw new SAXNotSupportedException (propertyId
);
540 declHandler
= (DeclHandler
) value
;
544 if ((PROPERTY
+ "lexical-handler").equals (propertyId
)) {
546 lexicalHandler
= base
;
547 else if (! (value
instanceof LexicalHandler
))
548 throw new SAXNotSupportedException (propertyId
);
550 lexicalHandler
= (LexicalHandler
) value
;
554 throw new SAXNotSupportedException (propertyId
);
559 // This is where the driver receives XmlParser callbacks and translates
560 // them into SAX callbacks. Some more callbacks have been added for
564 void startDocument ()
567 contentHandler
.setDocumentLocator (this);
568 contentHandler
.startDocument ();
569 attributesList
.clear ();
572 void xmlDecl(String version
,
575 String inputEncoding
)
578 if (contentHandler
instanceof ContentHandler2
)
580 ((ContentHandler2
) contentHandler
).xmlDecl(version
,
587 void skippedEntity (String name
)
589 { contentHandler
.skippedEntity (name
); }
591 InputSource
getExternalSubset (String name
, String baseURI
)
592 throws SAXException
, IOException
594 if (resolver2
== null || !useResolver2
|| !extPE
)
596 return resolver2
.getExternalSubset (name
, baseURI
);
599 InputSource
resolveEntity (boolean isPE
, String name
,
600 InputSource in
, String baseURI
)
601 throws SAXException
, IOException
605 // external entities might be skipped
612 lexicalHandler
.startEntity (name
);
613 if (resolver2
!= null && useResolver2
) {
614 source
= resolver2
.resolveEntity (name
, in
.getPublicId (),
615 baseURI
, in
.getSystemId ());
616 if (source
== null) {
617 in
.setSystemId (absolutize (baseURI
,
618 in
.getSystemId (), false));
622 in
.setSystemId (absolutize (baseURI
, in
.getSystemId (), false));
623 source
= entityResolver
.resolveEntity (in
.getPublicId (),
628 startExternalEntity (name
, source
.getSystemId (), true);
632 // absolutize a system ID relative to the specified base URI
633 // (temporarily) package-visible for external entity decls
634 String
absolutize (String baseURI
, String systemId
, boolean nice
)
635 throws MalformedURLException
, SAXException
637 // FIXME normalize system IDs -- when?
638 // - Convert to UTF-8
639 // - Map reserved and non-ASCII characters to %HH
642 if (baseURI
== null) {
643 warn ("No base URI; hope this SYSTEM id is absolute: "
645 return new URL (systemId
).toString ();
647 return new URL (new URL (baseURI
), systemId
).toString ();
649 } catch (MalformedURLException e
) {
651 // Let unknown URI schemes pass through unless we need
652 // the JVM to map them to i/o streams for us...
656 // sometimes sysids for notations or unparsed entities
657 // aren't really URIs...
658 warn ("Can't absolutize SYSTEM id: " + e
.getMessage ());
663 void startExternalEntity (String name
, String systemId
,
667 // The following warning was deleted because the application has the
668 // option of not setting systemId. Sun's JAXP or Xerces seems to
671 if (systemId == null)
672 warn ("URI was not reported to parser for entity " + name);
674 if (!stackOnly
) // spliced [dtd] needs startEntity
675 lexicalHandler
.startEntity (name
);
676 entityStack
.push (systemId
);
679 void endExternalEntity (String name
)
682 if (!"[document]".equals (name
))
683 lexicalHandler
.endEntity (name
);
687 void startInternalEntity (String name
)
690 lexicalHandler
.startEntity (name
);
693 void endInternalEntity (String name
)
696 lexicalHandler
.endEntity (name
);
699 void doctypeDecl (String name
, String publicId
, String systemId
)
702 lexicalHandler
.startDTD (name
, publicId
, systemId
);
704 // ... the "name" is a declaration and should be given
705 // to the DeclHandler (but sax2 doesn't).
707 // the IDs for the external subset are lexical details,
708 // as are the contents of the internal subset; but sax2
709 // doesn't provide the internal subset "pre-parse"
712 void notationDecl (String name
, String ids
[])
716 dtdHandler
.notationDecl (name
, ids
[0],
717 (resolveAll
&& ids
[1] != null)
718 ?
absolutize (ids
[2], ids
[1], true)
720 } catch (IOException e
) {
722 throw new SAXParseException (e
.getMessage (), this, e
);
726 void unparsedEntityDecl (String name
, String ids
[], String notation
)
730 dtdHandler
.unparsedEntityDecl (name
, ids
[0],
732 ?
absolutize (ids
[2], ids
[1], true)
735 } catch (IOException e
) {
737 throw new SAXParseException (e
.getMessage (), this, e
);
744 lexicalHandler
.endDTD ();
747 private void declarePrefix (String prefix
, String uri
)
750 int index
= uri
.indexOf (':');
752 // many versions of nwalsh docbook stylesheets
753 // have bogus URLs; so this can't be an error...
754 if (index
< 1 && uri
.length () != 0)
755 warn ("relative URI for namespace: " + uri
);
757 // FIXME: char [0] must be ascii alpha; chars [1..index]
758 // must be ascii alphanumeric or in "+-." [RFC 2396]
760 //Namespace Constraints
761 //name for xml prefix must be http://www.w3.org/XML/1998/namespace
762 boolean prefixEquality
= prefix
.equals("xml");
763 boolean uriEquality
= uri
.equals("http://www.w3.org/XML/1998/namespace");
764 if ((prefixEquality
|| uriEquality
) && !(prefixEquality
&& uriEquality
))
765 fatal ("xml is by definition bound to the namespace name " +
766 "http://www.w3.org/XML/1998/namespace");
768 //xmlns prefix declaration is illegal but xml prefix declaration is llegal...
769 if (prefixEquality
&& uriEquality
)
772 //name for xmlns prefix must be http://www.w3.org/2000/xmlns/
773 prefixEquality
= prefix
.equals("xmlns");
774 uriEquality
= uri
.equals("http://www.w3.org/2000/xmlns/");
775 if ((prefixEquality
|| uriEquality
) && !(prefixEquality
&& uriEquality
))
776 fatal("http://www.w3.org/2000/xmlns/ is by definition bound" +
779 //even if the uri is http://www.w3.org/2000/xmlns/ it is illegal to declare it
780 if (prefixEquality
&& uriEquality
)
781 fatal ("declaring the xmlns prefix is illegal");
784 prefixStack
.declarePrefix (prefix
, uri
);
785 contentHandler
.startPrefixMapping (prefix
, uri
);
788 void attribute (String qname
, String value
, boolean isSpecified
)
794 prefixStack
.pushContext ();
797 // process namespace decls immediately;
798 // then maybe forget this as an attribute
802 // default NS declaration?
803 if (getFeature (FEATURE
+ "string-interning")) {
804 if ("xmlns" == qname
) {
805 declarePrefix ("", value
);
809 // NS prefix declaration?
810 else if ((index
= qname
.indexOf (':')) == 5
811 && qname
.startsWith ("xmlns")) {
812 String prefix
= qname
.substring (6);
814 if (prefix
.equals(""))
815 fatal ("missing prefix in namespace declaration attribute");
816 if (value
.length () == 0) {
817 verror ("missing URI in namespace declaration attribute: "
820 declarePrefix (prefix
, value
);
825 if ("xmlns".equals(qname
)) {
826 declarePrefix ("", value
);
830 // NS prefix declaration?
831 else if ((index
= qname
.indexOf (':')) == 5
832 && qname
.startsWith ("xmlns")) {
833 String prefix
= qname
.substring (6);
835 if (value
.length () == 0) {
836 verror ("missing URI in namespace decl attribute: "
839 declarePrefix (prefix
, value
);
845 // remember this attribute ...
849 // attribute type comes from querying parser's DTD records
850 attributesList
.add(new Attribute(qname
, value
, isSpecified
));
854 void startElement (String elname
)
857 ContentHandler handler
= contentHandler
;
860 // NOTE: this implementation of namespace support adds something
861 // like six percent to parsing CPU time, in a large (~50 MB)
862 // document that doesn't use namespaces at all. (Measured by PC
863 // sampling, with a bug where endElement processing was omitted.)
864 // [Measurement referred to older implementation, older JVM ...]
866 // It ought to become notably faster in such cases. Most
867 // costs are the prefix stack calling Hashtable.get() (2%),
868 // String.hashCode() (1.5%) and about 1.3% each for pushing
869 // the context, and two chunks of name processing.
874 prefixStack
.pushContext ();
875 } else if (namespaces
) {
877 // now we can patch up namespace refs; we saw all the
878 // declarations, so now we'll do the Right Thing
879 Iterator itt
= attributesList
.iterator ();
882 Attribute attribute
= (Attribute
) itt
.next();
883 String qname
= attribute
.name
;
886 // default NS declaration?
887 if (getFeature (FEATURE
+ "string-interning")) {
888 if ("xmlns" == qname
)
891 if ("xmlns".equals(qname
))
894 //Illegal in the new Namespaces Draft
895 //should it be only in 1.1 docs??
896 if (qname
.equals (":"))
897 fatal ("namespace names consisting of a single colon " +
898 "character are invalid");
899 index
= qname
.indexOf (':');
901 // NS prefix declaration?
902 if (index
== 5 && qname
.startsWith ("xmlns"))
905 // it's not a NS decl; patch namespace info items
906 if (prefixStack
.processName (qname
, nsTemp
, true) == null)
907 fatal ("undeclared attribute prefix in: " + qname
);
909 attribute
.nameSpace
= nsTemp
[0];
910 attribute
.localName
= nsTemp
[1];
915 // save element name so attribute callbacks work
916 elementName
= elname
;
918 if (prefixStack
.processName (elname
, nsTemp
, false) == null) {
919 fatal ("undeclared element prefix in: " + elname
);
920 nsTemp
[0] = nsTemp
[1] = "";
922 handler
.startElement (nsTemp
[0], nsTemp
[1], elname
, this);
924 handler
.startElement ("", "", elname
, this);
925 // elementName = null;
927 // elements with no attributes are pretty common!
929 attributesList
.clear();
935 void endElement (String elname
)
938 ContentHandler handler
= contentHandler
;
941 handler
.endElement ("", "", elname
);
944 prefixStack
.processName (elname
, nsTemp
, false);
945 handler
.endElement (nsTemp
[0], nsTemp
[1], elname
);
947 Enumeration prefixes
= prefixStack
.getDeclaredPrefixes ();
949 while (prefixes
.hasMoreElements ())
950 handler
.endPrefixMapping ((String
) prefixes
.nextElement ());
951 prefixStack
.popContext ();
957 lexicalHandler
.startCDATA ();
960 void charData (char ch
[], int start
, int length
)
963 contentHandler
.characters (ch
, start
, length
);
969 lexicalHandler
.endCDATA ();
972 void ignorableWhitespace (char ch
[], int start
, int length
)
975 contentHandler
.ignorableWhitespace (ch
, start
, length
);
978 void processingInstruction (String target
, String data
)
981 contentHandler
.processingInstruction (target
, data
);
984 void comment (char ch
[], int start
, int length
)
987 if (lexicalHandler
!= base
)
988 lexicalHandler
.comment (ch
, start
, length
);
991 void fatal (String message
)
994 SAXParseException fatal
;
996 fatal
= new SAXParseException (message
, this);
997 errorHandler
.fatalError (fatal
);
999 // Even if the application can continue ... we can't!
1003 // We can safely report a few validity errors that
1004 // make layered SAX2 DTD validation more conformant
1005 void verror (String message
)
1008 SAXParseException err
;
1010 err
= new SAXParseException (message
, this);
1011 errorHandler
.error (err
);
1014 void warn (String message
)
1017 SAXParseException err
;
1019 err
= new SAXParseException (message
, this);
1020 errorHandler
.warning (err
);
1025 // Implementation of org.xml.sax.Attributes.
1029 * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1030 * (don't invoke on parser);
1032 public int getLength ()
1034 return attributesList
.size();
1038 * <b>SAX2 Attributes</b> method (don't invoke on parser);
1040 public String
getURI (int index
)
1042 if (index
< 0 || index
>= attributesList
.size())
1046 return ((Attribute
) attributesList
.get(index
)).nameSpace
;
1050 * <b>SAX2 Attributes</b> method (don't invoke on parser);
1052 public String
getLocalName (int index
)
1054 if (index
< 0 || index
>= attributesList
.size())
1058 Attribute attr
= (Attribute
) attributesList
.get(index
);
1059 // FIXME attr.localName is sometimes null, why?
1060 if (namespaces
&& attr
.localName
== null)
1062 // XXX fix this here for now
1063 int ci
= attr
.name
.indexOf(':');
1064 attr
.localName
= (ci
== -1) ? attr
.name
:
1065 attr
.name
.substring(ci
+ 1);
1067 return (attr
.localName
== null) ?
"" : attr
.localName
;
1071 * <b>SAX2 Attributes</b> method (don't invoke on parser);
1073 public String
getQName (int index
)
1075 if (index
< 0 || index
>= attributesList
.size())
1079 Attribute attr
= (Attribute
) attributesList
.get(index
);
1080 return (attr
.name
== null) ?
"" : attr
.name
;
1084 * <b>SAX1 AttributeList</b> method (don't invoke on parser);
1086 public String
getName (int index
)
1088 return getQName(index
);
1092 * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1093 * (don't invoke on parser);
1095 public String
getType (int index
)
1097 if (index
< 0 || index
>= attributesList
.size())
1101 String type
= parser
.getAttributeType(elementName
, getQName(index
));
1106 // ... use DeclHandler.attributeDecl to see enumerations
1107 if (type
== "ENUMERATION")
1116 * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1117 * (don't invoke on parser);
1119 public String
getValue (int index
)
1121 if (index
< 0 || index
>= attributesList
.size())
1125 return ((Attribute
) attributesList
.get(index
)).value
;
1130 * <b>SAX2 Attributes</b> method (don't invoke on parser);
1132 public int getIndex (String uri
, String local
)
1134 int length
= getLength();
1136 for (int i
= 0; i
< length
; i
++)
1138 if (!getURI(i
).equals(uri
))
1142 if (getLocalName(i
).equals(local
))
1152 * <b>SAX2 Attributes</b> method (don't invoke on parser);
1154 public int getIndex (String xmlName
)
1156 int length
= getLength();
1158 for (int i
= 0; i
< length
; i
++)
1160 if (getQName(i
).equals(xmlName
))
1170 * <b>SAX2 Attributes</b> method (don't invoke on parser);
1172 public String
getType (String uri
, String local
)
1174 int index
= getIndex(uri
, local
);
1180 return getType(index
);
1185 * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1186 * (don't invoke on parser);
1188 public String
getType (String xmlName
)
1190 int index
= getIndex(xmlName
);
1196 return getType(index
);
1201 * <b>SAX Attributes</b> method (don't invoke on parser);
1203 public String
getValue (String uri
, String local
)
1205 int index
= getIndex(uri
, local
);
1211 return getValue(index
);
1216 * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1217 * (don't invoke on parser);
1219 public String
getValue (String xmlName
)
1221 int index
= getIndex(xmlName
);
1227 return getValue(index
);
1232 // Implementation of org.xml.sax.ext.Attributes2
1236 /** @return false unless the attribute was declared in the DTD.
1237 * @throws java.lang.ArrayIndexOutOfBoundsException
1238 * When the supplied index does not identify an attribute.
1240 public boolean isDeclared (int index
)
1242 if (index
< 0 || index
>= attributeCount
)
1243 throw new ArrayIndexOutOfBoundsException ();
1244 String type
= parser
.getAttributeType(elementName
, getQName(index
));
1245 return (type
!= null);
1248 /** @return false unless the attribute was declared in the DTD.
1249 * @throws java.lang.IllegalArgumentException
1250 * When the supplied names do not identify an attribute.
1252 public boolean isDeclared (String qName
)
1254 int index
= getIndex (qName
);
1256 throw new IllegalArgumentException ();
1257 String type
= parser
.getAttributeType(elementName
, qName
);
1258 return (type
!= null);
1261 /** @return false unless the attribute was declared in the DTD.
1262 * @throws java.lang.IllegalArgumentException
1263 * When the supplied names do not identify an attribute.
1265 public boolean isDeclared (String uri
, String localName
)
1267 int index
= getIndex (uri
, localName
);
1268 return isDeclared(index
);
1273 * <b>SAX-ext Attributes2</b> method (don't invoke on parser);
1275 public boolean isSpecified (int index
)
1277 return ((Attribute
) attributesList
.get(index
)).specified
;
1281 * <b>SAX-ext Attributes2</b> method (don't invoke on parser);
1283 public boolean isSpecified (String uri
, String local
)
1285 int index
= getIndex (uri
, local
);
1286 return isSpecified(index
);
1290 * <b>SAX-ext Attributes2</b> method (don't invoke on parser);
1292 public boolean isSpecified (String xmlName
)
1294 int index
= getIndex (xmlName
);
1295 return isSpecified(index
);
1300 // Implementation of org.xml.sax.Locator.
1304 * <b>SAX Locator</b> method (don't invoke on parser);
1306 public String
getPublicId ()
1308 return null; // FIXME track public IDs too
1312 * <b>SAX Locator</b> method (don't invoke on parser);
1314 public String
getSystemId ()
1316 if (entityStack
.empty ())
1319 return (String
) entityStack
.peek ();
1323 * <b>SAX Locator</b> method (don't invoke on parser);
1325 public int getLineNumber ()
1327 return parser
.getLineNumber ();
1331 * <b>SAX Locator</b> method (don't invoke on parser);
1333 public int getColumnNumber ()
1335 return parser
.getColumnNumber ();
1338 // adapter between SAX2 content handler and SAX1 document handler callbacks
1339 private static class Adapter
implements ContentHandler
1341 private DocumentHandler docHandler
;
1343 Adapter (DocumentHandler dh
)
1344 { docHandler
= dh
; }
1347 public void setDocumentLocator (Locator l
)
1348 { docHandler
.setDocumentLocator (l
); }
1350 public void startDocument () throws SAXException
1351 { docHandler
.startDocument (); }
1353 public void processingInstruction (String target
, String data
)
1355 { docHandler
.processingInstruction (target
, data
); }
1357 public void startPrefixMapping (String prefix
, String uri
)
1360 public void startElement (
1365 ) throws SAXException
1366 { docHandler
.startElement (name
, (AttributeList
) attrs
); }
1368 public void characters (char buf
[], int offset
, int len
)
1370 { docHandler
.characters (buf
, offset
, len
); }
1372 public void ignorableWhitespace (char buf
[], int offset
, int len
)
1374 { docHandler
.ignorableWhitespace (buf
, offset
, len
); }
1376 public void skippedEntity (String name
)
1379 public void endElement (String u
, String l
, String name
)
1381 { docHandler
.endElement (name
); }
1383 public void endPrefixMapping (String prefix
)
1386 public void endDocument () throws SAXException
1387 { docHandler
.endDocument (); }
1400 Attribute(String name
, String value
, boolean specified
)
1404 this.nameSpace
= "";
1405 this.specified
= specified
;