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., 51 Franklin Street, Fifth Floor, 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 import java
.util
.ArrayList
;
64 import java
.util
.Collections
;
65 import java
.util
.Enumeration
;
66 import java
.util
.Iterator
;
67 import java
.util
.List
;
70 import org
.xml
.sax
.ext
.*;
71 import org
.xml
.sax
.helpers
.NamespaceSupport
;
75 * An enhanced SAX2 version of Microstar's Ælfred XML parser.
76 * The enhancements primarily relate to significant improvements in
77 * conformance to the XML specification, and SAX2 support. Performance
78 * has been improved. See the package level documentation for more
81 * <table border="1" width='100%' cellpadding='3' cellspacing='0'>
82 * <tr bgcolor='#ccccff'>
83 * <th><font size='+1'>Name</font></th>
84 * <th><font size='+1'>Notes</font></th></tr>
86 * <tr><td colspan=2><center><em>Features ... URL prefix is
87 * <b>http://xml.org/sax/features/</b></em></center></td></tr>
89 * <tr><td>(URL)/external-general-entities</td>
90 * <td>Value defaults to <em>true</em></td></tr>
91 * <tr><td>(URL)/external-parameter-entities</td>
92 * <td>Value defaults to <em>true</em></td></tr>
93 * <tr><td>(URL)/is-standalone</td>
94 * <td>(PRELIMINARY) Returns true iff the document's parsing
95 * has started (some non-error event after <em>startDocument()</em>
96 * was reported) and the document's standalone flag is set.</td></tr>
97 * <tr><td>(URL)/namespace-prefixes</td>
98 * <td>Value defaults to <em>false</em> (but XML 1.0 names are
99 * always reported)</td></tr>
100 * <tr><td>(URL)/lexical-handler/parameter-entities</td>
101 * <td>Value is fixed at <em>true</em></td></tr>
102 * <tr><td>(URL)/namespaces</td>
103 * <td>Value defaults to <em>true</em></td></tr>
104 * <tr><td>(URL)/resolve-dtd-uris</td>
105 * <td>(PRELIMINARY) Value defaults to <em>true</em></td></tr>
106 * <tr><td>(URL)/string-interning</td>
107 * <td>Value is fixed at <em>true</em></td></tr>
108 * <tr><td>(URL)/use-attributes2</td>
109 * <td>(PRELIMINARY) Value is fixed at <em>true</em></td></tr>
110 * <tr><td>(URL)/use-entity-resolver2</td>
111 * <td>(PRELIMINARY) Value defaults to <em>true</em></td></tr>
112 * <tr><td>(URL)/validation</td>
113 * <td>Value is fixed at <em>false</em></td></tr>
115 * <tr><td colspan=2><center><em>Handler Properties ... URL prefix is
116 * <b>http://xml.org/sax/properties/</b></em></center></td></tr>
118 * <tr><td>(URL)/declaration-handler</td>
119 * <td>A declaration handler may be provided. </td></tr>
120 * <tr><td>(URL)/lexical-handler</td>
121 * <td>A lexical handler may be provided. </td></tr>
124 * <p>This parser currently implements the SAX1 Parser API, but
125 * it may not continue to do so in the future.
127 * @author Written by David Megginson (version 1.2a from Microstar)
128 * @author Updated by David Brownell <dbrownell@users.sourceforge.net>
129 * @see org.xml.sax.Parser
131 final public class SAXDriver
132 implements Locator
, Attributes2
, XMLReader
, Parser
, AttributeList
135 private final DefaultHandler2 base
= new DefaultHandler2();
136 private XmlParser parser
;
138 private EntityResolver entityResolver
= base
;
139 private EntityResolver2 resolver2
= null;
140 private ContentHandler contentHandler
= base
;
141 private DTDHandler dtdHandler
= base
;
142 private ErrorHandler errorHandler
= base
;
143 private DeclHandler declHandler
= base
;
144 private LexicalHandler lexicalHandler
= base
;
146 private String elementName
;
147 private Stack entityStack
;
149 // one vector (of object/struct): faster, smaller
150 private List attributesList
;
152 private boolean namespaces
= true;
153 private boolean xmlNames
= false;
154 private boolean extGE
= true;
155 private boolean extPE
= true;
156 private boolean resolveAll
= true;
157 private boolean useResolver2
= true;
159 // package private to allow (read-only) access in XmlParser
160 boolean stringInterning
= true;
162 private int attributeCount
;
163 private boolean attributes
;
164 private String
[] nsTemp
;
165 private NamespaceSupport prefixStack
;
172 * Constructs a SAX Parser.
182 entityStack
= new Stack();
183 attributesList
= Collections
.synchronizedList(new ArrayList());
186 nsTemp
= new String
[3];
192 // Implementation of org.xml.sax.Parser.
196 * <b>SAX1</b>: Sets the locale used for diagnostics; currently,
197 * only locales using the English language are supported.
198 * @param locale The locale for which diagnostics will be generated
200 public void setLocale(Locale locale
)
203 if ("en".equals(locale
.getLanguage()))
207 throw new SAXException ("AElfred2 only supports English locales.");
211 * <b>SAX2</b>: Returns the object used when resolving external
212 * entities during parsing (both general and parameter entities).
214 public EntityResolver
getEntityResolver()
216 return (entityResolver
== base
) ?
null : entityResolver
;
220 * <b>SAX1, SAX2</b>: Set the entity resolver for this parser.
221 * @param handler The object to receive entity events.
223 public void setEntityResolver(EntityResolver resolver
)
225 if (resolver
instanceof EntityResolver2
)
227 resolver2
= (EntityResolver2
) resolver
;
233 if (resolver
== null)
237 entityResolver
= resolver
;
241 * <b>SAX2</b>: Returns the object used to process declarations related
242 * to notations and unparsed entities.
244 public DTDHandler
getDTDHandler()
246 return (dtdHandler
== base
) ?
null : dtdHandler
;
250 * <b>SAX1, SAX2</b>: Set the DTD handler for this parser.
251 * @param handler The object to receive DTD events.
253 public void setDTDHandler(DTDHandler handler
)
259 this.dtdHandler
= handler
;
264 * <b>SAX1</b>: Set the document handler for this parser. If a
265 * content handler was set, this document handler will supplant it.
266 * The parser is set to report all XML 1.0 names rather than to
267 * filter out "xmlns" attributes (the "namespace-prefixes" feature
270 * @deprecated SAX2 programs should use the XMLReader interface
271 * and a ContentHandler.
273 * @param handler The object to receive document events.
275 public void setDocumentHandler(DocumentHandler handler
)
277 contentHandler
= new Adapter(handler
);
282 * <b>SAX2</b>: Returns the object used to report the logical
283 * content of an XML document.
285 public ContentHandler
getContentHandler()
287 return (contentHandler
== base
) ?
null : contentHandler
;
291 * <b>SAX2</b>: Assigns the object used to report the logical
292 * content of an XML document. If a document handler was set,
293 * this content handler will supplant it (but XML 1.0 style name
294 * reporting may remain enabled).
296 public void setContentHandler(ContentHandler handler
)
302 contentHandler
= handler
;
306 * <b>SAX1, SAX2</b>: Set the error handler for this parser.
307 * @param handler The object to receive error events.
309 public void setErrorHandler(ErrorHandler handler
)
315 this.errorHandler
= handler
;
319 * <b>SAX2</b>: Returns the object used to receive callbacks for XML
320 * errors of all levels (fatal, nonfatal, warning); this is never null;
322 public ErrorHandler
getErrorHandler()
324 return (errorHandler
== base
) ?
null : errorHandler
;
328 * <b>SAX1, SAX2</b>: Auxiliary API to parse an XML document, used mostly
329 * when no URI is available.
330 * If you want anything useful to happen, you should set
331 * at least one type of handler.
332 * @param source The XML input source. Don't set 'encoding' unless
333 * you know for a fact that it's correct.
334 * @see #setEntityResolver
335 * @see #setDTDHandler
336 * @see #setContentHandler
337 * @see #setErrorHandler
338 * @exception SAXException The handlers may throw any SAXException,
339 * and the parser normally throws SAXParseException objects.
340 * @exception IOException IOExceptions are normally through through
341 * the parser if there are problems reading the source document.
343 public void parse(InputSource source
)
344 throws SAXException
, IOException
348 parser
= new XmlParser();
351 prefixStack
= new NamespaceSupport();
355 throw new IllegalStateException();
357 parser
.setHandler(this);
361 Reader r
= source
.getCharacterStream();
362 InputStream in
= source
.getByteStream();
364 parser
.doParse(source
.getSystemId(),
365 source
.getPublicId(),
368 source
.getEncoding());
370 catch (SAXException e
)
374 catch (IOException e
)
378 catch (RuntimeException e
)
384 throw new SAXParseException(e
.getMessage(), this, e
);
388 contentHandler
.endDocument();
395 * <b>SAX1, SAX2</b>: Preferred API to parse an XML document, using a
396 * system identifier (URI).
398 public void parse(String systemId
)
399 throws SAXException
, IOException
401 parse(new InputSource(systemId
));
405 // Implementation of SAX2 "XMLReader" interface
407 static final String FEATURE
= "http://xml.org/sax/features/";
408 static final String PROPERTY
= "http://xml.org/sax/properties/";
411 * <b>SAX2</b>: Tells the value of the specified feature flag.
413 * @exception SAXNotRecognizedException thrown if the feature flag
414 * is neither built in, nor yet assigned.
416 public boolean getFeature(String featureId
)
417 throws SAXNotRecognizedException
, SAXNotSupportedException
419 if ((FEATURE
+ "validation").equals(featureId
))
424 // external entities (both types) are optionally included
425 if ((FEATURE
+ "external-general-entities").equals(featureId
))
429 if ((FEATURE
+ "external-parameter-entities").equals(featureId
))
434 // element/attribute names are as written in document; no mangling
435 if ((FEATURE
+ "namespace-prefixes").equals(featureId
))
440 // report element/attribute namespaces?
441 if ((FEATURE
+ "namespaces").equals(featureId
))
446 // all PEs and GEs are reported
447 if ((FEATURE
+ "lexical-handler/parameter-entities").equals(featureId
))
453 if ((FEATURE
+ "string-interning").equals(featureId
))
455 return stringInterning
;
460 // always returns isSpecified info
461 if ((FEATURE
+ "use-attributes2").equals(featureId
))
466 // meaningful between startDocument/endDocument
467 if ((FEATURE
+ "is-standalone").equals(featureId
))
471 throw new SAXNotSupportedException(featureId
);
473 return parser
.isStandalone();
476 // optionally don't absolutize URIs in declarations
477 if ((FEATURE
+ "resolve-dtd-uris").equals(featureId
))
482 // optionally use resolver2 interface methods, if possible
483 if ((FEATURE
+ "use-entity-resolver2").equals(featureId
))
488 throw new SAXNotRecognizedException(featureId
);
492 DeclHandler
getDeclHandler()
498 boolean resolveURIs()
504 * <b>SAX2</b>: Returns the specified property.
506 * @exception SAXNotRecognizedException thrown if the property value
507 * is neither built in, nor yet stored.
509 public Object
getProperty(String propertyId
)
510 throws SAXNotRecognizedException
512 if ((PROPERTY
+ "declaration-handler").equals(propertyId
))
514 return (declHandler
== base
) ?
null : declHandler
;
517 if ((PROPERTY
+ "lexical-handler").equals(propertyId
))
519 return (lexicalHandler
== base
) ?
null : lexicalHandler
;
522 // unknown properties
523 throw new SAXNotRecognizedException(propertyId
);
527 * <b>SAX2</b>: Sets the state of feature flags in this parser. Some
528 * built-in feature flags are mutable.
530 public void setFeature(String featureId
, boolean value
)
531 throws SAXNotRecognizedException
, SAXNotSupportedException
535 // Features with a defined value, we just change it if we can.
536 state
= getFeature (featureId
);
544 throw new SAXNotSupportedException("not while parsing");
547 if ((FEATURE
+ "namespace-prefixes").equals(featureId
))
549 // in this implementation, this only affects xmlns reporting
551 // forcibly prevent illegal parser state
559 if ((FEATURE
+ "namespaces").equals(featureId
))
562 // forcibly prevent illegal parser state
570 if ((FEATURE
+ "external-general-entities").equals(featureId
))
575 if ((FEATURE
+ "external-parameter-entities").equals(featureId
))
580 if ((FEATURE
+ "resolve-dtd-uris").equals(featureId
))
586 if ((FEATURE
+ "use-entity-resolver2").equals(featureId
))
588 useResolver2
= value
;
592 throw new SAXNotRecognizedException(featureId
);
596 * <b>SAX2</b>: Assigns the specified property. Like SAX1 handlers,
597 * these may be changed at any time.
599 public void setProperty(String propertyId
, Object value
)
600 throws SAXNotRecognizedException
, SAXNotSupportedException
602 // see if the property is recognized
603 getProperty(propertyId
);
605 // Properties with a defined value, we just change it if we can.
607 if ((PROPERTY
+ "declaration-handler").equals(propertyId
))
613 else if (!(value
instanceof DeclHandler
))
615 throw new SAXNotSupportedException(propertyId
);
619 declHandler
= (DeclHandler
) value
;
624 if ((PROPERTY
+ "lexical-handler").equals(propertyId
))
628 lexicalHandler
= base
;
630 else if (!(value
instanceof LexicalHandler
))
632 throw new SAXNotSupportedException(propertyId
);
636 lexicalHandler
= (LexicalHandler
) value
;
641 throw new SAXNotSupportedException(propertyId
);
645 // This is where the driver receives XmlParser callbacks and translates
646 // them into SAX callbacks. Some more callbacks have been added for
653 contentHandler
.setDocumentLocator(this);
654 contentHandler
.startDocument();
655 attributesList
.clear();
658 void xmlDecl(String version
,
661 String inputEncoding
)
664 if (contentHandler
instanceof ContentHandler2
)
666 ((ContentHandler2
) contentHandler
).xmlDecl(version
,
673 void skippedEntity(String name
)
676 contentHandler
.skippedEntity(name
);
679 InputSource
getExternalSubset(String name
, String baseURI
)
680 throws SAXException
, IOException
682 if (resolver2
== null || !useResolver2
|| !extPE
)
686 return resolver2
.getExternalSubset(name
, baseURI
);
689 InputSource
resolveEntity(boolean isPE
, String name
,
690 InputSource in
, String baseURI
)
691 throws SAXException
, IOException
695 // external entities might be skipped
706 lexicalHandler
.startEntity(name
);
707 if (resolver2
!= null && useResolver2
)
709 source
= resolver2
.resolveEntity(name
, in
.getPublicId(),
710 baseURI
, in
.getSystemId());
713 in
.setSystemId(absolutize(baseURI
,
714 in
.getSystemId(), false));
720 in
.setSystemId(absolutize(baseURI
,
722 entityResolver
!= base
));
723 source
= entityResolver
.resolveEntity(in
.getPublicId(),
730 startExternalEntity(name
, source
.getSystemId(), true);
734 // absolutize a system ID relative to the specified base URI
735 // (temporarily) package-visible for external entity decls
736 String
absolutize(String baseURI
, String systemId
, boolean nice
)
737 throws MalformedURLException
, SAXException
739 // FIXME normalize system IDs -- when?
740 // - Convert to UTF-8
741 // - Map reserved and non-ASCII characters to %HH
747 if (XmlParser
.uriWarnings
)
749 warn ("No base URI; hope this SYSTEM id is absolute: "
752 return new URL(systemId
).toString();
756 return new URL(new URL(baseURI
), systemId
).toString();
759 catch (MalformedURLException e
)
761 // Let unknown URI schemes pass through unless we need
762 // the JVM to map them to i/o streams for us...
768 // sometimes sysids for notations or unparsed entities
769 // aren't really URIs...
770 warn("Can't absolutize SYSTEM id: " + e
.getMessage());
775 void startExternalEntity(String name
, String systemId
, boolean stackOnly
)
778 // The following warning was deleted because the application has the
779 // option of not setting systemId. Sun's JAXP or Xerces seems to
782 if (systemId == null)
783 warn ("URI was not reported to parser for entity " + name);
785 if (!stackOnly
) // spliced [dtd] needs startEntity
787 lexicalHandler
.startEntity(name
);
789 entityStack
.push(systemId
);
792 void endExternalEntity(String name
)
795 if (!"[document]".equals(name
))
797 lexicalHandler
.endEntity(name
);
802 void startInternalEntity(String name
)
805 lexicalHandler
.startEntity(name
);
808 void endInternalEntity(String name
)
811 lexicalHandler
.endEntity(name
);
814 void doctypeDecl(String name
, String publicId
, String systemId
)
817 lexicalHandler
.startDTD(name
, publicId
, systemId
);
819 // ... the "name" is a declaration and should be given
820 // to the DeclHandler (but sax2 doesn't).
822 // the IDs for the external subset are lexical details,
823 // as are the contents of the internal subset; but sax2
824 // doesn't provide the internal subset "pre-parse"
827 void notationDecl(String name
, String publicId
, String systemId
,
833 dtdHandler
.notationDecl(name
, publicId
,
834 (resolveAll
&& systemId
!= null)
835 ?
absolutize(baseUri
, systemId
, true)
838 catch (IOException e
)
841 throw new SAXParseException(e
.getMessage(), this, e
);
845 void unparsedEntityDecl(String name
, String publicId
, String systemId
,
846 String baseUri
, String notation
)
851 dtdHandler
.unparsedEntityDecl(name
, publicId
,
853 ?
absolutize(baseUri
, systemId
, true)
857 catch (IOException e
)
860 throw new SAXParseException(e
.getMessage(), this, e
);
867 lexicalHandler
.endDTD();
870 private void declarePrefix(String prefix
, String uri
)
873 int index
= uri
.indexOf(':');
875 // many versions of nwalsh docbook stylesheets
876 // have bogus URLs; so this can't be an error...
877 if (index
< 1 && uri
.length() != 0)
879 warn("relative URI for namespace: " + uri
);
882 // FIXME: char [0] must be ascii alpha; chars [1..index]
883 // must be ascii alphanumeric or in "+-." [RFC 2396]
885 //Namespace Constraints
886 //name for xml prefix must be http://www.w3.org/XML/1998/namespace
887 boolean prefixEquality
= prefix
.equals("xml");
888 boolean uriEquality
= uri
.equals("http://www.w3.org/XML/1998/namespace");
889 if ((prefixEquality
|| uriEquality
) && !(prefixEquality
&& uriEquality
))
891 fatal("xml is by definition bound to the namespace name " +
892 "http://www.w3.org/XML/1998/namespace");
895 //xmlns prefix declaration is illegal but xml prefix declaration is llegal...
896 if (prefixEquality
&& uriEquality
)
901 //name for xmlns prefix must be http://www.w3.org/2000/xmlns/
902 prefixEquality
= prefix
.equals("xmlns");
903 uriEquality
= uri
.equals("http://www.w3.org/2000/xmlns/");
904 if ((prefixEquality
|| uriEquality
) && !(prefixEquality
&& uriEquality
))
906 fatal("http://www.w3.org/2000/xmlns/ is by definition bound" +
910 //even if the uri is http://www.w3.org/2000/xmlns/
911 // it is illegal to declare it
912 if (prefixEquality
&& uriEquality
)
914 fatal ("declaring the xmlns prefix is illegal");
918 prefixStack
.declarePrefix(prefix
, uri
);
919 contentHandler
.startPrefixMapping(prefix
, uri
);
922 void attribute(String qname
, String value
, boolean isSpecified
)
930 prefixStack
.pushContext();
934 // process namespace decls immediately;
935 // then maybe forget this as an attribute
940 // default NS declaration?
943 if ("xmlns" == qname
)
945 declarePrefix("", value
);
951 // NS prefix declaration?
952 else if ((index
= qname
.indexOf(':')) == 5
953 && qname
.startsWith("xmlns"))
955 String prefix
= qname
.substring(6);
957 if (prefix
.equals(""))
959 fatal("missing prefix " +
960 "in namespace declaration attribute");
962 if (value
.length() == 0)
964 verror("missing URI in namespace declaration attribute: "
969 declarePrefix(prefix
, value
);
979 if ("xmlns".equals(qname
))
981 declarePrefix("", value
);
987 // NS prefix declaration?
988 else if ((index
= qname
.indexOf(':')) == 5
989 && qname
.startsWith("xmlns"))
991 String prefix
= qname
.substring(6);
993 if (value
.length() == 0)
995 verror("missing URI in namespace decl attribute: "
1000 declarePrefix(prefix
, value
);
1009 // remember this attribute ...
1012 // attribute type comes from querying parser's DTD records
1013 attributesList
.add(new Attribute(qname
, value
, isSpecified
));
1017 void startElement(String elname
)
1020 ContentHandler handler
= contentHandler
;
1023 // NOTE: this implementation of namespace support adds something
1024 // like six percent to parsing CPU time, in a large (~50 MB)
1025 // document that doesn't use namespaces at all. (Measured by PC
1026 // sampling, with a bug where endElement processing was omitted.)
1027 // [Measurement referred to older implementation, older JVM ...]
1029 // It ought to become notably faster in such cases. Most
1030 // costs are the prefix stack calling Hashtable.get() (2%),
1031 // String.hashCode() (1.5%) and about 1.3% each for pushing
1032 // the context, and two chunks of name processing.
1039 prefixStack
.pushContext();
1042 else if (namespaces
)
1045 // now we can patch up namespace refs; we saw all the
1046 // declarations, so now we'll do the Right Thing
1047 Iterator itt
= attributesList
.iterator();
1048 while (itt
.hasNext())
1050 Attribute attribute
= (Attribute
) itt
.next();
1051 String qname
= attribute
.name
;
1054 // default NS declaration?
1055 if (stringInterning
)
1057 if ("xmlns" == qname
)
1064 if ("xmlns".equals(qname
))
1069 //Illegal in the new Namespaces Draft
1070 //should it be only in 1.1 docs??
1071 if (qname
.equals (":"))
1073 fatal("namespace names consisting of a single colon " +
1074 "character are invalid");
1076 index
= qname
.indexOf(':');
1078 // NS prefix declaration?
1079 if (index
== 5 && qname
.startsWith("xmlns"))
1084 // it's not a NS decl; patch namespace info items
1085 if (prefixStack
.processName(qname
, nsTemp
, true) == null)
1087 fatal("undeclared attribute prefix in: " + qname
);
1091 attribute
.nameSpace
= nsTemp
[0];
1092 attribute
.localName
= nsTemp
[1];
1097 // save element name so attribute callbacks work
1098 elementName
= elname
;
1101 if (prefixStack
.processName(elname
, nsTemp
, false) == null)
1103 fatal("undeclared element prefix in: " + elname
);
1104 nsTemp
[0] = nsTemp
[1] = "";
1106 handler
.startElement(nsTemp
[0], nsTemp
[1], elname
, this);
1110 handler
.startElement("", "", elname
, this);
1112 // elementName = null;
1114 // elements with no attributes are pretty common!
1117 attributesList
.clear();
1123 void endElement(String elname
)
1126 ContentHandler handler
= contentHandler
;
1130 handler
.endElement("", "", elname
);
1133 prefixStack
.processName(elname
, nsTemp
, false);
1134 handler
.endElement(nsTemp
[0], nsTemp
[1], elname
);
1136 Enumeration prefixes
= prefixStack
.getDeclaredPrefixes();
1138 while (prefixes
.hasMoreElements())
1140 handler
.endPrefixMapping((String
) prefixes
.nextElement());
1142 prefixStack
.popContext();
1148 lexicalHandler
.startCDATA();
1151 void charData(char[] ch
, int start
, int length
)
1154 contentHandler
.characters(ch
, start
, length
);
1160 lexicalHandler
.endCDATA();
1163 void ignorableWhitespace(char[] ch
, int start
, int length
)
1166 contentHandler
.ignorableWhitespace(ch
, start
, length
);
1169 void processingInstruction(String target
, String data
)
1172 contentHandler
.processingInstruction(target
, data
);
1175 void comment(char[] ch
, int start
, int length
)
1178 if (lexicalHandler
!= base
)
1180 lexicalHandler
.comment(ch
, start
, length
);
1184 void fatal(String message
)
1187 SAXParseException fatal
;
1189 fatal
= new SAXParseException(message
, this);
1190 errorHandler
.fatalError(fatal
);
1192 // Even if the application can continue ... we can't!
1196 // We can safely report a few validity errors that
1197 // make layered SAX2 DTD validation more conformant
1198 void verror(String message
)
1201 SAXParseException err
;
1203 err
= new SAXParseException(message
, this);
1204 errorHandler
.error(err
);
1207 void warn(String message
)
1210 SAXParseException err
;
1212 err
= new SAXParseException(message
, this);
1213 errorHandler
.warning(err
);
1217 // Implementation of org.xml.sax.Attributes.
1221 * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1222 * (don't invoke on parser);
1224 public int getLength()
1226 return attributesList
.size();
1230 * <b>SAX2 Attributes</b> method (don't invoke on parser);
1232 public String
getURI(int index
)
1234 if (index
< 0 || index
>= attributesList
.size())
1238 return ((Attribute
) attributesList
.get(index
)).nameSpace
;
1242 * <b>SAX2 Attributes</b> method (don't invoke on parser);
1244 public String
getLocalName(int index
)
1246 if (index
< 0 || index
>= attributesList
.size())
1250 Attribute attr
= (Attribute
) attributesList
.get(index
);
1251 // FIXME attr.localName is sometimes null, why?
1252 if (namespaces
&& attr
.localName
== null)
1254 // XXX fix this here for now
1255 int ci
= attr
.name
.indexOf(':');
1256 attr
.localName
= (ci
== -1) ? attr
.name
:
1257 attr
.name
.substring(ci
+ 1);
1259 return (attr
.localName
== null) ?
"" : attr
.localName
;
1263 * <b>SAX2 Attributes</b> method (don't invoke on parser);
1265 public String
getQName(int index
)
1267 if (index
< 0 || index
>= attributesList
.size())
1271 Attribute attr
= (Attribute
) attributesList
.get(index
);
1272 return (attr
.name
== null) ?
"" : attr
.name
;
1276 * <b>SAX1 AttributeList</b> method (don't invoke on parser);
1278 public String
getName(int index
)
1280 return getQName(index
);
1284 * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1285 * (don't invoke on parser);
1287 public String
getType(int index
)
1289 if (index
< 0 || index
>= attributesList
.size())
1293 String type
= parser
.getAttributeType(elementName
, getQName(index
));
1298 // ... use DeclHandler.attributeDecl to see enumerations
1299 if (type
== "ENUMERATION")
1307 * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1308 * (don't invoke on parser);
1310 public String
getValue(int index
)
1312 if (index
< 0 || index
>= attributesList
.size())
1316 return ((Attribute
) attributesList
.get(index
)).value
;
1320 * <b>SAX2 Attributes</b> method (don't invoke on parser);
1322 public int getIndex(String uri
, String local
)
1324 int length
= getLength();
1326 for (int i
= 0; i
< length
; i
++)
1328 if (!getURI(i
).equals(uri
))
1332 if (getLocalName(i
).equals(local
))
1341 * <b>SAX2 Attributes</b> method (don't invoke on parser);
1343 public int getIndex(String xmlName
)
1345 int length
= getLength();
1347 for (int i
= 0; i
< length
; i
++)
1349 if (getQName(i
).equals(xmlName
))
1358 * <b>SAX2 Attributes</b> method (don't invoke on parser);
1360 public String
getType(String uri
, String local
)
1362 int index
= getIndex(uri
, local
);
1368 return getType(index
);
1372 * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1373 * (don't invoke on parser);
1375 public String
getType(String xmlName
)
1377 int index
= getIndex(xmlName
);
1383 return getType(index
);
1387 * <b>SAX Attributes</b> method (don't invoke on parser);
1389 public String
getValue(String uri
, String local
)
1391 int index
= getIndex(uri
, local
);
1397 return getValue(index
);
1401 * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1402 * (don't invoke on parser);
1404 public String
getValue(String xmlName
)
1406 int index
= getIndex(xmlName
);
1412 return getValue(index
);
1416 // Implementation of org.xml.sax.ext.Attributes2
1419 /** @return false unless the attribute was declared in the DTD.
1420 * @throws java.lang.ArrayIndexOutOfBoundsException
1421 * When the supplied index does not identify an attribute.
1423 public boolean isDeclared(int index
)
1425 if (index
< 0 || index
>= attributeCount
)
1427 throw new ArrayIndexOutOfBoundsException();
1429 String type
= parser
.getAttributeType(elementName
, getQName(index
));
1430 return (type
!= null);
1433 /** @return false unless the attribute was declared in the DTD.
1434 * @throws java.lang.IllegalArgumentException
1435 * When the supplied names do not identify an attribute.
1437 public boolean isDeclared(String qName
)
1439 int index
= getIndex(qName
);
1442 throw new IllegalArgumentException();
1444 String type
= parser
.getAttributeType(elementName
, qName
);
1445 return (type
!= null);
1448 /** @return false unless the attribute was declared in the DTD.
1449 * @throws java.lang.IllegalArgumentException
1450 * When the supplied names do not identify an attribute.
1452 public boolean isDeclared(String uri
, String localName
)
1454 int index
= getIndex(uri
, localName
);
1455 return isDeclared(index
);
1459 * <b>SAX-ext Attributes2</b> method (don't invoke on parser);
1461 public boolean isSpecified(int index
)
1463 return ((Attribute
) attributesList
.get(index
)).specified
;
1467 * <b>SAX-ext Attributes2</b> method (don't invoke on parser);
1469 public boolean isSpecified(String uri
, String local
)
1471 int index
= getIndex (uri
, local
);
1472 return isSpecified(index
);
1476 * <b>SAX-ext Attributes2</b> method (don't invoke on parser);
1478 public boolean isSpecified(String xmlName
)
1480 int index
= getIndex (xmlName
);
1481 return isSpecified(index
);
1485 // Implementation of org.xml.sax.Locator.
1489 * <b>SAX Locator</b> method (don't invoke on parser);
1491 public String
getPublicId()
1493 return null; // FIXME track public IDs too
1497 * <b>SAX Locator</b> method (don't invoke on parser);
1499 public String
getSystemId()
1501 if (entityStack
.empty())
1507 return (String
) entityStack
.peek();
1512 * <b>SAX Locator</b> method (don't invoke on parser);
1514 public int getLineNumber()
1516 return parser
.getLineNumber();
1520 * <b>SAX Locator</b> method (don't invoke on parser);
1522 public int getColumnNumber()
1524 return parser
.getColumnNumber();
1527 // adapter between SAX2 content handler and SAX1 document handler callbacks
1528 private static class Adapter
1529 implements ContentHandler
1532 private DocumentHandler docHandler
;
1534 Adapter(DocumentHandler dh
)
1539 public void setDocumentLocator(Locator l
)
1541 docHandler
.setDocumentLocator(l
);
1544 public void startDocument()
1547 docHandler
.startDocument();
1550 public void processingInstruction(String target
, String data
)
1553 docHandler
.processingInstruction(target
, data
);
1556 public void startPrefixMapping(String prefix
, String uri
)
1561 public void startElement(String namespace
,
1567 docHandler
.startElement(name
, (AttributeList
) attrs
);
1570 public void characters(char[] buf
, int offset
, int len
)
1573 docHandler
.characters(buf
, offset
, len
);
1576 public void ignorableWhitespace(char[] buf
, int offset
, int len
)
1579 docHandler
.ignorableWhitespace(buf
, offset
, len
);
1582 public void skippedEntity(String name
)
1587 public void endElement(String u
, String l
, String name
)
1590 docHandler
.endElement(name
);
1593 public void endPrefixMapping(String prefix
)
1598 public void endDocument()
1601 docHandler
.endDocument();
1605 private static class Attribute
1614 Attribute(String name
, String value
, boolean specified
)
1618 this.nameSpace
= "";
1619 this.specified
= specified
;