Imported GNU Classpath 0.19 + gcj-import-20051115.
[official-gcc.git] / libjava / classpath / gnu / xml / aelfred2 / SAXDriver.java
blob6864ff659711587f0b6c393b4d8a460752cf9625
1 /* SAXDriver.java --
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)
9 any later version.
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
19 02110-1301 USA.
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
24 combination.
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
51 YOUR OWN RISK.
54 package gnu.xml.aelfred2;
56 import java.io.*;
58 import java.net.MalformedURLException;
59 import java.net.URL;
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;
69 import org.xml.sax.*;
70 import org.xml.sax.ext.*;
71 import org.xml.sax.helpers.NamespaceSupport;
74 /**
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
79 * information.
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>
122 * </table>
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 &lt;dbrownell@users.sourceforge.net&gt;
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;
168 // Constructor.
172 * Constructs a SAX Parser.
174 public SAXDriver()
176 reset();
179 private void reset()
181 elementName = null;
182 entityStack = new Stack();
183 attributesList = Collections.synchronizedList(new ArrayList());
184 attributeCount = 0;
185 attributes = false;
186 nsTemp = new String[3];
187 prefixStack = null;
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)
201 throws SAXException
203 if ("en".equals(locale.getLanguage()))
205 return;
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;
229 else
231 resolver2 = null;
233 if (resolver == null)
235 resolver = base;
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)
255 if (handler == null)
257 handler = base;
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
268 * is set to true).
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);
278 xmlNames = true;
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)
298 if (handler == null)
300 handler = base;
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)
311 if (handler == null)
313 handler = base;
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
346 synchronized (base)
348 parser = new XmlParser();
349 if (namespaces)
351 prefixStack = new NamespaceSupport();
353 else if (!xmlNames)
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)
372 throw e;
374 catch (IOException e)
376 throw e;
378 catch (RuntimeException e)
380 throw e;
382 catch (Exception e)
384 throw new SAXParseException(e.getMessage(), this, e);
386 finally
388 contentHandler.endDocument();
389 reset();
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))
421 return false;
424 // external entities (both types) are optionally included
425 if ((FEATURE + "external-general-entities").equals(featureId))
427 return extGE;
429 if ((FEATURE + "external-parameter-entities").equals(featureId))
431 return extPE;
434 // element/attribute names are as written in document; no mangling
435 if ((FEATURE + "namespace-prefixes").equals(featureId))
437 return xmlNames;
440 // report element/attribute namespaces?
441 if ((FEATURE + "namespaces").equals(featureId))
443 return namespaces;
446 // all PEs and GEs are reported
447 if ((FEATURE + "lexical-handler/parameter-entities").equals(featureId))
449 return true;
452 // default is true
453 if ((FEATURE + "string-interning").equals(featureId))
455 return stringInterning;
458 // EXTENSIONS 1.1
460 // always returns isSpecified info
461 if ((FEATURE + "use-attributes2").equals(featureId))
463 return true;
466 // meaningful between startDocument/endDocument
467 if ((FEATURE + "is-standalone").equals(featureId))
469 if (parser == null)
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))
479 return resolveAll;
482 // optionally use resolver2 interface methods, if possible
483 if ((FEATURE + "use-entity-resolver2").equals(featureId))
485 return useResolver2;
488 throw new SAXNotRecognizedException(featureId);
491 // package private
492 DeclHandler getDeclHandler()
494 return declHandler;
497 // package private
498 boolean resolveURIs()
500 return resolveAll;
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
533 boolean state;
535 // Features with a defined value, we just change it if we can.
536 state = getFeature (featureId);
538 if (state == value)
540 return;
542 if (parser != null)
544 throw new SAXNotSupportedException("not while parsing");
547 if ((FEATURE + "namespace-prefixes").equals(featureId))
549 // in this implementation, this only affects xmlns reporting
550 xmlNames = value;
551 // forcibly prevent illegal parser state
552 if (!xmlNames)
554 namespaces = true;
556 return;
559 if ((FEATURE + "namespaces").equals(featureId))
561 namespaces = value;
562 // forcibly prevent illegal parser state
563 if (!namespaces)
565 xmlNames = true;
567 return;
570 if ((FEATURE + "external-general-entities").equals(featureId))
572 extGE = value;
573 return;
575 if ((FEATURE + "external-parameter-entities").equals(featureId))
577 extPE = value;
578 return;
580 if ((FEATURE + "resolve-dtd-uris").equals(featureId))
582 resolveAll = value;
583 return;
586 if ((FEATURE + "use-entity-resolver2").equals(featureId))
588 useResolver2 = value;
589 return;
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))
609 if (value == null)
611 declHandler = base;
613 else if (!(value instanceof DeclHandler))
615 throw new SAXNotSupportedException(propertyId);
617 else
619 declHandler = (DeclHandler) value;
621 return ;
624 if ((PROPERTY + "lexical-handler").equals(propertyId))
626 if (value == null)
628 lexicalHandler = base;
630 else if (!(value instanceof LexicalHandler))
632 throw new SAXNotSupportedException(propertyId);
634 else
636 lexicalHandler = (LexicalHandler) value;
638 return;
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
647 // SAX2 support.
650 void startDocument()
651 throws SAXException
653 contentHandler.setDocumentLocator(this);
654 contentHandler.startDocument();
655 attributesList.clear();
658 void xmlDecl(String version,
659 String encoding,
660 boolean standalone,
661 String inputEncoding)
662 throws SAXException
664 if (contentHandler instanceof ContentHandler2)
666 ((ContentHandler2) contentHandler).xmlDecl(version,
667 encoding,
668 standalone,
669 inputEncoding);
673 void skippedEntity(String name)
674 throws SAXException
676 contentHandler.skippedEntity(name);
679 InputSource getExternalSubset(String name, String baseURI)
680 throws SAXException, IOException
682 if (resolver2 == null || !useResolver2 || !extPE)
684 return null;
686 return resolver2.getExternalSubset(name, baseURI);
689 InputSource resolveEntity(boolean isPE, String name,
690 InputSource in, String baseURI)
691 throws SAXException, IOException
693 InputSource source;
695 // external entities might be skipped
696 if (isPE && !extPE)
698 return null;
700 if (!isPE && !extGE)
702 return null;
705 // ... or not
706 lexicalHandler.startEntity(name);
707 if (resolver2 != null && useResolver2)
709 source = resolver2.resolveEntity(name, in.getPublicId(),
710 baseURI, in.getSystemId());
711 if (source == null)
713 in.setSystemId(absolutize(baseURI,
714 in.getSystemId(), false));
715 source = in;
718 else
720 in.setSystemId(absolutize(baseURI,
721 in.getSystemId(),
722 entityResolver != base));
723 source = entityResolver.resolveEntity(in.getPublicId(),
724 in.getSystemId());
725 if (source == null)
727 source = in;
730 startExternalEntity(name, source.getSystemId(), true);
731 return source;
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
745 if (baseURI == null)
747 if (XmlParser.uriWarnings)
749 warn ("No base URI; hope this SYSTEM id is absolute: "
750 + systemId);
752 return new URL(systemId).toString();
754 else
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...
763 if (!nice)
765 throw e;
768 // sometimes sysids for notations or unparsed entities
769 // aren't really URIs...
770 warn("Can't absolutize SYSTEM id: " + e.getMessage());
771 return systemId;
775 void startExternalEntity(String name, String systemId, boolean stackOnly)
776 throws SAXException
778 // The following warning was deleted because the application has the
779 // option of not setting systemId. Sun's JAXP or Xerces seems to
780 // ignore this case.
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)
793 throws SAXException
795 if (!"[document]".equals(name))
797 lexicalHandler.endEntity(name);
799 entityStack.pop();
802 void startInternalEntity(String name)
803 throws SAXException
805 lexicalHandler.startEntity(name);
808 void endInternalEntity(String name)
809 throws SAXException
811 lexicalHandler.endEntity(name);
814 void doctypeDecl(String name, String publicId, String systemId)
815 throws SAXException
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,
828 String baseUri)
829 throws SAXException
833 dtdHandler.notationDecl(name, publicId,
834 (resolveAll && systemId != null)
835 ? absolutize(baseUri, systemId, true)
836 : systemId);
838 catch (IOException e)
840 // "can't happen"
841 throw new SAXParseException(e.getMessage(), this, e);
845 void unparsedEntityDecl(String name, String publicId, String systemId,
846 String baseUri, String notation)
847 throws SAXException
851 dtdHandler.unparsedEntityDecl(name, publicId,
852 resolveAll
853 ? absolutize(baseUri, systemId, true)
854 : systemId,
855 notation);
857 catch (IOException e)
859 // "can't happen"
860 throw new SAXParseException(e.getMessage(), this, e);
864 void endDoctype()
865 throws SAXException
867 lexicalHandler.endDTD();
870 private void declarePrefix(String prefix, String uri)
871 throws SAXException
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)
898 return;
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" +
907 " to prefix xmlns");
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");
917 uri = uri.intern();
918 prefixStack.declarePrefix(prefix, uri);
919 contentHandler.startPrefixMapping(prefix, uri);
922 void attribute(String qname, String value, boolean isSpecified)
923 throws SAXException
925 if (!attributes)
927 attributes = true;
928 if (namespaces)
930 prefixStack.pushContext();
934 // process namespace decls immediately;
935 // then maybe forget this as an attribute
936 if (namespaces)
938 int index;
940 // default NS declaration?
941 if (stringInterning)
943 if ("xmlns" == qname)
945 declarePrefix("", value);
946 if (!xmlNames)
948 return;
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: "
965 + qname);
967 else
969 declarePrefix(prefix, value);
971 if (!xmlNames)
973 return;
977 else
979 if ("xmlns".equals(qname))
981 declarePrefix("", value);
982 if (!xmlNames)
984 return;
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: "
996 + qname);
998 else
1000 declarePrefix(prefix, value);
1002 if (!xmlNames)
1004 return;
1009 // remember this attribute ...
1010 attributeCount++;
1012 // attribute type comes from querying parser's DTD records
1013 attributesList.add(new Attribute(qname, value, isSpecified));
1017 void startElement(String elname)
1018 throws SAXException
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.
1035 if (!attributes)
1037 if (namespaces)
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;
1052 int index;
1054 // default NS declaration?
1055 if (stringInterning)
1057 if ("xmlns" == qname)
1059 continue;
1062 else
1064 if ("xmlns".equals(qname))
1066 continue;
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"))
1081 continue;
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);
1089 else
1091 attribute.nameSpace = nsTemp[0];
1092 attribute.localName = nsTemp[1];
1097 // save element name so attribute callbacks work
1098 elementName = elname;
1099 if (namespaces)
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);
1108 else
1110 handler.startElement("", "", elname, this);
1112 // elementName = null;
1114 // elements with no attributes are pretty common!
1115 if (attributes)
1117 attributesList.clear();
1118 attributeCount = 0;
1119 attributes = false;
1123 void endElement(String elname)
1124 throws SAXException
1126 ContentHandler handler = contentHandler;
1128 if (!namespaces)
1130 handler.endElement("", "", elname);
1131 return;
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();
1145 void startCDATA()
1146 throws SAXException
1148 lexicalHandler.startCDATA();
1151 void charData(char[] ch, int start, int length)
1152 throws SAXException
1154 contentHandler.characters(ch, start, length);
1157 void endCDATA()
1158 throws SAXException
1160 lexicalHandler.endCDATA();
1163 void ignorableWhitespace(char[] ch, int start, int length)
1164 throws SAXException
1166 contentHandler.ignorableWhitespace(ch, start, length);
1169 void processingInstruction(String target, String data)
1170 throws SAXException
1172 contentHandler.processingInstruction(target, data);
1175 void comment(char[] ch, int start, int length)
1176 throws SAXException
1178 if (lexicalHandler != base)
1180 lexicalHandler.comment(ch, start, length);
1184 void fatal(String message)
1185 throws SAXException
1187 SAXParseException fatal;
1189 fatal = new SAXParseException(message, this);
1190 errorHandler.fatalError(fatal);
1192 // Even if the application can continue ... we can't!
1193 throw fatal;
1196 // We can safely report a few validity errors that
1197 // make layered SAX2 DTD validation more conformant
1198 void verror(String message)
1199 throws SAXException
1201 SAXParseException err;
1203 err = new SAXParseException(message, this);
1204 errorHandler.error(err);
1207 void warn(String message)
1208 throws SAXException
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())
1236 return null;
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())
1248 return null;
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())
1269 return null;
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())
1291 return null;
1293 String type = parser.getAttributeType(elementName, getQName(index));
1294 if (type == null)
1296 return "CDATA";
1298 // ... use DeclHandler.attributeDecl to see enumerations
1299 if (type == "ENUMERATION")
1301 return "NMTOKEN";
1303 return type;
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())
1314 return null;
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))
1330 continue;
1332 if (getLocalName(i).equals(local))
1334 return i;
1337 return -1;
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))
1351 return i;
1354 return -1;
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);
1364 if (index < 0)
1366 return null;
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);
1379 if (index < 0)
1381 return null;
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);
1393 if (index < 0)
1395 return null;
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);
1408 if (index < 0)
1410 return null;
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);
1440 if (index < 0)
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())
1503 return null;
1505 else
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)
1536 docHandler = dh;
1539 public void setDocumentLocator(Locator l)
1541 docHandler.setDocumentLocator(l);
1544 public void startDocument()
1545 throws SAXException
1547 docHandler.startDocument();
1550 public void processingInstruction(String target, String data)
1551 throws SAXException
1553 docHandler.processingInstruction(target, data);
1556 public void startPrefixMapping(String prefix, String uri)
1558 /* ignored */
1561 public void startElement(String namespace,
1562 String local,
1563 String name,
1564 Attributes attrs)
1565 throws SAXException
1567 docHandler.startElement(name, (AttributeList) attrs);
1570 public void characters(char[] buf, int offset, int len)
1571 throws SAXException
1573 docHandler.characters(buf, offset, len);
1576 public void ignorableWhitespace(char[] buf, int offset, int len)
1577 throws SAXException
1579 docHandler.ignorableWhitespace(buf, offset, len);
1582 public void skippedEntity(String name)
1584 /* ignored */
1587 public void endElement(String u, String l, String name)
1588 throws SAXException
1590 docHandler.endElement(name);
1593 public void endPrefixMapping(String prefix)
1595 /* ignored */
1598 public void endDocument()
1599 throws SAXException
1601 docHandler.endDocument();
1605 private static class Attribute
1608 String name;
1609 String value;
1610 String nameSpace;
1611 String localName;
1612 boolean specified;
1614 Attribute(String name, String value, boolean specified)
1616 this.name = name;
1617 this.value = value;
1618 this.nameSpace = "";
1619 this.specified = specified;