Save This Page
Home » openjdk-7 » com.sun.org.apache.xerces.internal » parsers » [javadoc | source]
    1   /*
    2    * reserved comment block
    3    * DO NOT REMOVE OR ALTER!
    4    */
    5   /*
    6    * Copyright 2001-2005 The Apache Software Foundation.
    7    *
    8    * Licensed under the Apache License, Version 2.0 (the "License");
    9    * you may not use this file except in compliance with the License.
   10    * You may obtain a copy of the License at
   11    *
   12    *      http://www.apache.org/licenses/LICENSE-2.0
   13    *
   14    * Unless required by applicable law or agreed to in writing, software
   15    * distributed under the License is distributed on an "AS IS" BASIS,
   16    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   17    * See the License for the specific language governing permissions and
   18    * limitations under the License.
   19    */
   20   
   21   package com.sun.org.apache.xerces.internal.parsers;
   22   
   23   import java.io.IOException;
   24   import java.util.Locale;
   25   
   26   import com.sun.org.apache.xerces.internal.impl.Constants;
   27   import com.sun.org.apache.xerces.internal.xs.PSVIProvider;
   28   import com.sun.org.apache.xerces.internal.util.EntityResolverWrapper;
   29   import com.sun.org.apache.xerces.internal.util.EntityResolver2Wrapper;
   30   import com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper;
   31   import com.sun.org.apache.xerces.internal.util.SAXMessageFormatter;
   32   import com.sun.org.apache.xerces.internal.util.SymbolHash;
   33   import com.sun.org.apache.xerces.internal.util.XMLSymbols;
   34   import com.sun.org.apache.xerces.internal.xni.Augmentations;
   35   import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
   36   import com.sun.org.apache.xerces.internal.xni.QName;
   37   import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
   38   import com.sun.org.apache.xerces.internal.xni.XMLLocator;
   39   import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
   40   import com.sun.org.apache.xerces.internal.xni.XMLString;
   41   import com.sun.org.apache.xerces.internal.xni.XNIException;
   42   import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
   43   import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver;
   44   import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler;
   45   import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
   46   import com.sun.org.apache.xerces.internal.xni.parser.XMLParseException;
   47   import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration;
   48   import com.sun.org.apache.xerces.internal.xs.AttributePSVI;
   49   import com.sun.org.apache.xerces.internal.xs.ElementPSVI;
   50   import org.xml.sax.AttributeList;
   51   import org.xml.sax.Attributes;
   52   import org.xml.sax.ContentHandler;
   53   import org.xml.sax.DTDHandler;
   54   import org.xml.sax.DocumentHandler;
   55   import org.xml.sax.EntityResolver;
   56   import org.xml.sax.ErrorHandler;
   57   import org.xml.sax.InputSource;
   58   import org.xml.sax.Locator;
   59   import org.xml.sax.Parser;
   60   import org.xml.sax.SAXException;
   61   import org.xml.sax.SAXNotRecognizedException;
   62   import org.xml.sax.SAXNotSupportedException;
   63   import org.xml.sax.SAXParseException;
   64   import org.xml.sax.XMLReader;
   65   import org.xml.sax.ext.Attributes2;
   66   import org.xml.sax.ext.DeclHandler;
   67   import org.xml.sax.ext.EntityResolver2;
   68   import org.xml.sax.ext.LexicalHandler;
   69   import org.xml.sax.ext.Locator2;
   70   import org.xml.sax.helpers.LocatorImpl;
   71   
   72   /**
   73    * This is the base class of all SAX parsers. It implements both the
   74    * SAX1 and SAX2 parser functionality, while the actual pipeline is
   75    * defined in the parser configuration.
   76    *
   77    * @author Arnaud Le Hors, IBM
   78    * @author Andy Clark, IBM
   79    *
   80    */
   81   public abstract class AbstractSAXParser
   82       extends AbstractXMLDocumentParser
   83       implements PSVIProvider, // PSVI
   84                 Parser, XMLReader // SAX1, SAX2
   85   {
   86   
   87       //
   88       // Constants
   89       //
   90   
   91       // features
   92   
   93       /** Feature identifier: namespaces. */
   94       protected static final String NAMESPACES =
   95           Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE;
   96   
   97       /** Feature identifier: namespace prefixes. */
   98       protected static final String NAMESPACE_PREFIXES =
   99           Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACE_PREFIXES_FEATURE;
  100   
  101       /** Feature id: string interning. */
  102       protected static final String STRING_INTERNING =
  103           Constants.SAX_FEATURE_PREFIX + Constants.STRING_INTERNING_FEATURE;
  104   
  105       /** Feature identifier: allow notation and unparsed entity events to be sent out of order. */
  106       // this is not meant to be a recognized feature, but we need it here to use
  107       // if it is already a recognized feature for the pipeline
  108       protected static final String ALLOW_UE_AND_NOTATION_EVENTS =
  109           Constants.SAX_FEATURE_PREFIX + Constants.ALLOW_DTD_EVENTS_AFTER_ENDDTD_FEATURE;
  110   
  111       /** Recognized features. */
  112       private static final String[] RECOGNIZED_FEATURES = {
  113           NAMESPACES,
  114           NAMESPACE_PREFIXES,
  115           STRING_INTERNING,
  116       };
  117   
  118       // properties
  119   
  120       /** Property id: lexical handler. */
  121       protected static final String LEXICAL_HANDLER =
  122           Constants.SAX_PROPERTY_PREFIX + Constants.LEXICAL_HANDLER_PROPERTY;
  123   
  124       /** Property id: declaration handler. */
  125       protected static final String DECLARATION_HANDLER =
  126           Constants.SAX_PROPERTY_PREFIX + Constants.DECLARATION_HANDLER_PROPERTY;
  127   
  128       /** Property id: DOM node. */
  129       protected static final String DOM_NODE =
  130           Constants.SAX_PROPERTY_PREFIX + Constants.DOM_NODE_PROPERTY;
  131   
  132       /** Recognized properties. */
  133       private static final String[] RECOGNIZED_PROPERTIES = {
  134           LEXICAL_HANDLER,
  135           DECLARATION_HANDLER,
  136           DOM_NODE,
  137       };
  138   
  139       //
  140       // Data
  141       //
  142   
  143       // features
  144   
  145       /** Namespaces. */
  146       protected boolean fNamespaces;
  147   
  148       /** Namespace prefixes. */
  149       protected boolean fNamespacePrefixes = false;
  150   
  151       /** Lexical handler parameter entities. */
  152       protected boolean fLexicalHandlerParameterEntities = true;
  153   
  154       /** Standalone document declaration. */
  155       protected boolean fStandalone;
  156   
  157       /** Resolve DTD URIs. */
  158       protected boolean fResolveDTDURIs = true;
  159   
  160       /** Use EntityResolver2. */
  161       protected boolean fUseEntityResolver2 = true;
  162   
  163       /**
  164        * XMLNS URIs: Namespace declarations in the
  165        * http://www.w3.org/2000/xmlns/ namespace.
  166        */
  167       protected boolean fXMLNSURIs = false;
  168   
  169       // parser handlers
  170   
  171       /** Content handler. */
  172       protected ContentHandler fContentHandler;
  173   
  174       /** Document handler. */
  175       protected DocumentHandler fDocumentHandler;
  176   
  177       /** Namespace context */
  178       protected NamespaceContext fNamespaceContext;
  179   
  180       /** DTD handler. */
  181       protected org.xml.sax.DTDHandler fDTDHandler;
  182   
  183       /** Decl handler. */
  184       protected DeclHandler fDeclHandler;
  185   
  186       /** Lexical handler. */
  187       protected LexicalHandler fLexicalHandler;
  188   
  189       protected QName fQName = new QName();
  190   
  191       // state
  192   
  193       /**
  194        * True if a parse is in progress. This state is needed because
  195        * some features/properties cannot be set while parsing (e.g.
  196        * validation and namespaces).
  197        */
  198       protected boolean fParseInProgress = false;
  199   
  200       // track the version of the document being parsed
  201       protected String fVersion;
  202   
  203       // temp vars
  204       private final AttributesProxy fAttributesProxy = new AttributesProxy();
  205       private Augmentations fAugmentations = null;
  206   
  207   
  208       // temporary buffer for sending normalized values
  209       // REVISIT: what should be the size of the buffer?
  210       private static final int BUFFER_SIZE = 20;
  211       private char[] fCharBuffer =  new char[BUFFER_SIZE];
  212   
  213       // allows us to keep track of whether an attribute has
  214       // been declared twice, so that we can avoid exposing the
  215       // second declaration to any registered DeclHandler
  216       protected SymbolHash fDeclaredAttrs = null;
  217   
  218       //
  219       // Constructors
  220       //
  221   
  222       /** Default constructor. */
  223       protected AbstractSAXParser(XMLParserConfiguration config) {
  224           super(config);
  225   
  226           config.addRecognizedFeatures(RECOGNIZED_FEATURES);
  227           config.addRecognizedProperties(RECOGNIZED_PROPERTIES);
  228   
  229           try {
  230               config.setFeature(ALLOW_UE_AND_NOTATION_EVENTS, false);
  231           }
  232           catch (XMLConfigurationException e) {
  233               // it wasn't a recognized feature, so we don't worry about it
  234           }
  235       } // <init>(XMLParserConfiguration)
  236   
  237       //
  238       // XMLDocumentHandler methods
  239       //
  240   
  241       /**
  242        * The start of the document.
  243        *
  244        * @param locator The document locator, or null if the document
  245        *                 location cannot be reported during the parsing
  246        *                 of this document. However, it is <em>strongly</em>
  247        *                 recommended that a locator be supplied that can
  248        *                 at least report the system identifier of the
  249        *                 document.
  250        * @param encoding The auto-detected IANA encoding name of the entity
  251        *                 stream. This value will be null in those situations
  252        *                 where the entity encoding is not auto-detected (e.g.
  253        *                 internal entities or a document entity that is
  254        *                 parsed from a java.io.Reader).
  255        * @param namespaceContext
  256        *                 The namespace context in effect at the
  257        *                 start of this document.
  258        *                 This object represents the current context.
  259        *                 Implementors of this class are responsible
  260        *                 for copying the namespace bindings from the
  261        *                 the current context (and its parent contexts)
  262        *                 if that information is important.
  263        * @param augs     Additional information that may include infoset augmentations
  264        *
  265        * @throws XNIException Thrown by handler to signal an error.
  266        */
  267       public void startDocument(XMLLocator locator, String encoding,
  268                                 NamespaceContext namespaceContext, Augmentations augs)
  269           throws XNIException {
  270   
  271           fNamespaceContext = namespaceContext;
  272   
  273           try {
  274               // SAX1
  275               if (fDocumentHandler != null) {
  276                   if (locator != null) {
  277                       fDocumentHandler.setDocumentLocator(new LocatorProxy(locator));
  278                   }
  279                   fDocumentHandler.startDocument();
  280               }
  281   
  282               // SAX2
  283               if (fContentHandler != null) {
  284                   if (locator != null) {
  285                       fContentHandler.setDocumentLocator(new LocatorProxy(locator));
  286                   }
  287                   fContentHandler.startDocument();
  288               }
  289           }
  290           catch (SAXException e) {
  291               throw new XNIException(e);
  292           }
  293   
  294       } // startDocument(locator,encoding,augs)
  295   
  296       /**
  297        * Notifies of the presence of an XMLDecl line in the document. If
  298        * present, this method will be called immediately following the
  299        * startDocument call.
  300        *
  301        * @param version    The XML version.
  302        * @param encoding   The IANA encoding name of the document, or null if
  303        *                   not specified.
  304        * @param standalone The standalone value, or null if not specified.
  305        * @param augs   Additional information that may include infoset augmentations
  306        *
  307        * @throws XNIException Thrown by handler to signal an error.
  308        */
  309       public void xmlDecl(String version, String encoding, String standalone, Augmentations augs)
  310           throws XNIException {
  311           // the version need only be set once; if
  312           // document's XML 1.0|1.1, that's how it'll stay
  313           fVersion = version;
  314           fStandalone = "yes".equals(standalone);
  315       } // xmlDecl(String,String,String)
  316   
  317       /**
  318        * Notifies of the presence of the DOCTYPE line in the document.
  319        *
  320        * @param rootElement The name of the root element.
  321        * @param publicId    The public identifier if an external DTD or null
  322        *                    if the external DTD is specified using SYSTEM.
  323        * @param systemId    The system identifier if an external DTD, null
  324        *                    otherwise.
  325        * @param augs     Additional information that may include infoset augmentations
  326        *
  327        * @throws XNIException Thrown by handler to signal an error.
  328        */
  329       public void doctypeDecl(String rootElement,
  330                               String publicId, String systemId, Augmentations augs)
  331           throws XNIException {
  332           fInDTD = true;
  333   
  334           try {
  335               // SAX2 extension
  336               if (fLexicalHandler != null) {
  337                   fLexicalHandler.startDTD(rootElement, publicId, systemId);
  338               }
  339           }
  340           catch (SAXException e) {
  341               throw new XNIException(e);
  342           }
  343   
  344           // is there a DeclHandler?
  345           if(fDeclHandler != null) {
  346               fDeclaredAttrs = new SymbolHash();
  347           }
  348   
  349       } // doctypeDecl(String,String,String)
  350   
  351           /**
  352        * This method notifies of the start of an entity. The DTD has the
  353        * pseudo-name of "[dtd]" parameter entity names start with '%'; and
  354        * general entity names are just the entity name.
  355        * <p>
  356        * <strong>Note:</strong> Since the document is an entity, the handler
  357        * will be notified of the start of the document entity by calling the
  358        * startEntity method with the entity name "[xml]" <em>before</em> calling
  359        * the startDocument method. When exposing entity boundaries through the
  360        * SAX API, the document entity is never reported, however.
  361        * <p>
  362        * <strong>Note:</strong> This method is not called for entity references
  363        * appearing as part of attribute values.
  364        *
  365        * @param name     The name of the entity.
  366        * @param identifier The resource identifier.
  367        * @param encoding The auto-detected IANA encoding name of the entity
  368        *                 stream. This value will be null in those situations
  369        *                 where the entity encoding is not auto-detected (e.g.
  370        *                 internal parameter entities).
  371        * @param augs     Additional information that may include infoset augmentations
  372        *
  373        * @throws XNIException Thrown by handler to signal an error.
  374        */
  375       public void startGeneralEntity(String name, XMLResourceIdentifier identifier,
  376                                      String encoding, Augmentations augs)
  377           throws XNIException {
  378   
  379           try {
  380               // Only report startEntity if this entity was actually read.
  381               if (augs != null && Boolean.TRUE.equals(augs.getItem(Constants.ENTITY_SKIPPED))) {
  382                   // report skipped entity to content handler
  383                   if (fContentHandler != null) {
  384                       fContentHandler.skippedEntity(name);
  385                   }
  386               }
  387               else {
  388                   // SAX2 extension
  389                   if (fLexicalHandler != null) {
  390                       fLexicalHandler.startEntity(name);
  391                   }
  392               }
  393           }
  394           catch (SAXException e) {
  395               throw new XNIException(e);
  396           }
  397   
  398       } // startGeneralEntity(String,String,String,String,String)
  399   
  400       /**
  401        * This method notifies the end of an entity. The DTD has the pseudo-name
  402        * of "[dtd]" parameter entity names start with '%'; and general entity
  403        * names are just the entity name.
  404        * <p>
  405        * <strong>Note:</strong> Since the document is an entity, the handler
  406        * will be notified of the end of the document entity by calling the
  407        * endEntity method with the entity name "[xml]" <em>after</em> calling
  408        * the endDocument method. When exposing entity boundaries through the
  409        * SAX API, the document entity is never reported, however.
  410        * <p>
  411        * <strong>Note:</strong> This method is not called for entity references
  412        * appearing as part of attribute values.
  413        *
  414        * @param name The name of the entity.
  415        * @param augs     Additional information that may include infoset augmentations
  416        *
  417        * @throws XNIException Thrown by handler to signal an error.
  418        */
  419       public void endGeneralEntity(String name, Augmentations augs) throws XNIException {
  420   
  421           try {
  422               // Only report endEntity if this entity was actually read.
  423               if (augs == null || !Boolean.TRUE.equals(augs.getItem(Constants.ENTITY_SKIPPED))) {
  424                   // SAX2 extension
  425                   if (fLexicalHandler != null) {
  426                       fLexicalHandler.endEntity(name);
  427                   }
  428               }
  429           }
  430           catch (SAXException e) {
  431               throw new XNIException(e);
  432           }
  433   
  434       } // endEntity(String)
  435   
  436        /**
  437        * The start of an element. If the document specifies the start element
  438        * by using an empty tag, then the startElement method will immediately
  439        * be followed by the endElement method, with no intervening methods.
  440        *
  441        * @param element    The name of the element.
  442        * @param attributes The element attributes.
  443        * @param augs     Additional information that may include infoset augmentations
  444        *
  445        * @throws XNIException Thrown by handler to signal an error.
  446        */
  447       public void startElement(QName element, XMLAttributes attributes, Augmentations augs)
  448           throws XNIException {
  449   
  450           try {
  451               // SAX1
  452               if (fDocumentHandler != null) {
  453                   // REVISIT: should we support schema-normalized-value for SAX1 events
  454                   //
  455                   fAttributesProxy.setAttributes(attributes);
  456                   fDocumentHandler.startElement(element.rawname, fAttributesProxy);
  457               }
  458   
  459               // SAX2
  460               if (fContentHandler != null) {
  461   
  462                   if (fNamespaces) {
  463                       // send prefix mapping events
  464                       startNamespaceMapping();
  465   
  466                       // REVISIT: It should not be necessary to iterate over the attribute
  467                       // list when the set of [namespace attributes] is empty for this
  468                       // element. This should be computable from the NamespaceContext, but
  469                       // since we currently don't report the mappings for the xml prefix
  470                       // we cannot use the declared prefix count for the current context
  471                       // to skip this section. -- mrglavas
  472                       int len = attributes.getLength();
  473                       if (!fNamespacePrefixes) {
  474                           for (int i = len - 1; i >= 0; --i) {
  475                               attributes.getName(i, fQName);
  476                               if ((fQName.prefix == XMLSymbols.PREFIX_XMLNS) ||
  477                                  (fQName.rawname == XMLSymbols.PREFIX_XMLNS)) {
  478                                   // remove namespace declaration attributes
  479                                   attributes.removeAttributeAt(i);
  480                               }
  481                           }
  482                       }
  483                       else if (!fXMLNSURIs) {
  484                           for (int i = len - 1; i >= 0; --i) {
  485                               attributes.getName(i, fQName);
  486                               if ((fQName.prefix == XMLSymbols.PREFIX_XMLNS) ||
  487                                  (fQName.rawname == XMLSymbols.PREFIX_XMLNS)) {
  488                                   // localpart should be empty string as per SAX documentation:
  489                                   // http://www.saxproject.org/?selected=namespaces
  490                                   fQName.prefix = "";
  491                                   fQName.uri = "";
  492                                   fQName.localpart = "";
  493                                   attributes.setName(i, fQName);
  494                               }
  495                           }
  496                       }
  497                   }
  498   
  499                   fAugmentations = augs;
  500   
  501                   String uri = element.uri != null ? element.uri : "";
  502                   String localpart = fNamespaces ? element.localpart : "";
  503                   fAttributesProxy.setAttributes(attributes);
  504                   fContentHandler.startElement(uri, localpart, element.rawname,
  505                                                fAttributesProxy);
  506               }
  507           }
  508           catch (SAXException e) {
  509               throw new XNIException(e);
  510           }
  511   
  512       } // startElement(QName,XMLAttributes)
  513   
  514       /**
  515        * Character content.
  516        *
  517        * @param text The content.
  518        * @param augs     Additional information that may include infoset augmentations
  519        *
  520        * @throws XNIException Thrown by handler to signal an error.
  521        */
  522       public void characters(XMLString text, Augmentations augs) throws XNIException {
  523   
  524           // if type is union (XML Schema) it is possible that we receive
  525           // character call with empty data
  526           if (text.length == 0) {
  527               return;
  528           }
  529   
  530   
  531           try {
  532               // SAX1
  533               if (fDocumentHandler != null) {
  534                   // REVISIT: should we support schema-normalized-value for SAX1 events
  535                   //
  536                   fDocumentHandler.characters(text.ch, text.offset, text.length);
  537               }
  538   
  539               // SAX2
  540               if (fContentHandler != null) {
  541                   fContentHandler.characters(text.ch, text.offset, text.length);
  542               }
  543           }
  544           catch (SAXException e) {
  545               throw new XNIException(e);
  546           }
  547   
  548       } // characters(XMLString)
  549   
  550       /**
  551        * Ignorable whitespace. For this method to be called, the document
  552        * source must have some way of determining that the text containing
  553        * only whitespace characters should be considered ignorable. For
  554        * example, the validator can determine if a length of whitespace
  555        * characters in the document are ignorable based on the element
  556        * content model.
  557        *
  558        * @param text The ignorable whitespace.
  559        * @param augs     Additional information that may include infoset augmentations
  560        *
  561        * @throws XNIException Thrown by handler to signal an error.
  562        */
  563       public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException {
  564   
  565           try {
  566               // SAX1
  567               if (fDocumentHandler != null) {
  568                   fDocumentHandler.ignorableWhitespace(text.ch, text.offset, text.length);
  569               }
  570   
  571               // SAX2
  572               if (fContentHandler != null) {
  573                   fContentHandler.ignorableWhitespace(text.ch, text.offset, text.length);
  574               }
  575           }
  576           catch (SAXException e) {
  577               throw new XNIException(e);
  578           }
  579   
  580       } // ignorableWhitespace(XMLString)
  581   
  582       /**
  583        * The end of an element.
  584        *
  585        * @param element The name of the element.
  586        * @param augs     Additional information that may include infoset augmentations
  587        *
  588        * @throws XNIException Thrown by handler to signal an error.
  589        */
  590       public void endElement(QName element, Augmentations augs) throws XNIException {
  591   
  592   
  593           try {
  594               // SAX1
  595               if (fDocumentHandler != null) {
  596                   fDocumentHandler.endElement(element.rawname);
  597               }
  598   
  599               // SAX2
  600               if (fContentHandler != null) {
  601                   fAugmentations = augs;
  602                   String uri = element.uri != null ? element.uri : "";
  603                   String localpart = fNamespaces ? element.localpart : "";
  604                   fContentHandler.endElement(uri, localpart,
  605                                              element.rawname);
  606                   if (fNamespaces) {
  607                       endNamespaceMapping();
  608                   }
  609               }
  610           }
  611           catch (SAXException e) {
  612               throw new XNIException(e);
  613           }
  614   
  615       } // endElement(QName)
  616   
  617           /**
  618        * The start of a CDATA section.
  619        * @param augs     Additional information that may include infoset augmentations
  620        *
  621        * @throws XNIException Thrown by handler to signal an error.
  622        */
  623       public void startCDATA(Augmentations augs) throws XNIException {
  624   
  625           try {
  626               // SAX2 extension
  627               if (fLexicalHandler != null) {
  628                   fLexicalHandler.startCDATA();
  629               }
  630           }
  631           catch (SAXException e) {
  632               throw new XNIException(e);
  633           }
  634   
  635       } // startCDATA()
  636   
  637       /**
  638        * The end of a CDATA section.
  639        * @param augs     Additional information that may include infoset augmentations
  640        *
  641        * @throws XNIException Thrown by handler to signal an error.
  642        */
  643       public void endCDATA(Augmentations augs) throws XNIException {
  644   
  645           try {
  646               // SAX2 extension
  647               if (fLexicalHandler != null) {
  648                   fLexicalHandler.endCDATA();
  649               }
  650           }
  651           catch (SAXException e) {
  652               throw new XNIException(e);
  653           }
  654   
  655       } // endCDATA()
  656   
  657       /**
  658        * A comment.
  659        *
  660        * @param text The text in the comment.
  661        * @param augs     Additional information that may include infoset augmentations
  662        *
  663        * @throws XNIException Thrown by application to signal an error.
  664        */
  665       public void comment(XMLString text, Augmentations augs) throws XNIException {
  666   
  667           try {
  668               // SAX2 extension
  669               if (fLexicalHandler != null) {
  670                   fLexicalHandler.comment(text.ch, 0, text.length);
  671               }
  672           }
  673           catch (SAXException e) {
  674               throw new XNIException(e);
  675           }
  676   
  677       } // comment(XMLString)
  678   
  679       /**
  680        * A processing instruction. Processing instructions consist of a
  681        * target name and, optionally, text data. The data is only meaningful
  682        * to the application.
  683        * <p>
  684        * Typically, a processing instruction's data will contain a series
  685        * of pseudo-attributes. These pseudo-attributes follow the form of
  686        * element attributes but are <strong>not</strong> parsed or presented
  687        * to the application as anything other than text. The application is
  688        * responsible for parsing the data.
  689        *
  690        * @param target The target.
  691        * @param data   The data or null if none specified.
  692        * @param augs     Additional information that may include infoset augmentations
  693        *
  694        * @throws XNIException Thrown by handler to signal an error.
  695        */
  696       public void processingInstruction(String target, XMLString data, Augmentations augs)
  697           throws XNIException {
  698   
  699           //
  700           // REVISIT - I keep running into SAX apps that expect
  701           //   null data to be an empty string, which is contrary
  702           //   to the comment for this method in the SAX API.
  703           //
  704   
  705           try {
  706               // SAX1
  707               if (fDocumentHandler != null) {
  708                   fDocumentHandler.processingInstruction(target,
  709                                                          data.toString());
  710               }
  711   
  712               // SAX2
  713               if (fContentHandler != null) {
  714                   fContentHandler.processingInstruction(target, data.toString());
  715               }
  716           }
  717           catch (SAXException e) {
  718               throw new XNIException(e);
  719           }
  720   
  721       } // processingInstruction(String,XMLString)
  722   
  723   
  724       /**
  725        * The end of the document.
  726        * @param augs     Additional information that may include infoset augmentations
  727        *
  728        * @throws XNIException Thrown by handler to signal an error.
  729        */
  730       public void endDocument(Augmentations augs) throws XNIException {
  731   
  732           try {
  733               // SAX1
  734               if (fDocumentHandler != null) {
  735                   fDocumentHandler.endDocument();
  736               }
  737   
  738               // SAX2
  739               if (fContentHandler != null) {
  740                   fContentHandler.endDocument();
  741               }
  742           }
  743           catch (SAXException e) {
  744               throw new XNIException(e);
  745           }
  746   
  747       } // endDocument()
  748   
  749       //
  750       // XMLDTDHandler methods
  751       //
  752   
  753       /**
  754        * The start of the DTD external subset.
  755        *
  756        * @param augs Additional information that may include infoset
  757        *                      augmentations.
  758        *
  759        * @throws XNIException Thrown by handler to signal an error.
  760        */
  761       public void startExternalSubset(XMLResourceIdentifier identifier,
  762                                       Augmentations augs) throws XNIException {
  763           startParameterEntity("[dtd]", null, null, augs);
  764       }
  765   
  766       /**
  767        * The end of the DTD external subset.
  768        *
  769        * @param augs Additional information that may include infoset
  770        *                      augmentations.
  771        *
  772        * @throws XNIException Thrown by handler to signal an error.
  773        */
  774       public void endExternalSubset(Augmentations augs) throws XNIException {
  775           endParameterEntity("[dtd]", augs);
  776       }
  777   
  778       /**
  779        * This method notifies of the start of parameter entity. The DTD has the
  780        * pseudo-name of "[dtd]" parameter entity names start with '%'; and
  781        * general entity names are just the entity name.
  782        * <p>
  783        * <strong>Note:</strong> Since the document is an entity, the handler
  784        * will be notified of the start of the document entity by calling the
  785        * startEntity method with the entity name "[xml]" <em>before</em> calling
  786        * the startDocument method. When exposing entity boundaries through the
  787        * SAX API, the document entity is never reported, however.
  788        * <p>
  789        * <strong>Note:</strong> This method is not called for entity references
  790        * appearing as part of attribute values.
  791        *
  792        * @param name     The name of the parameter entity.
  793        * @param identifier The resource identifier.
  794        * @param encoding The auto-detected IANA encoding name of the entity
  795        *                 stream. This value will be null in those situations
  796        *                 where the entity encoding is not auto-detected (e.g.
  797        *                 internal parameter entities).
  798        * @param augs Additional information that may include infoset
  799        *                      augmentations.
  800        *
  801        * @throws XNIException Thrown by handler to signal an error.
  802        */
  803       public void startParameterEntity(String name,
  804                                        XMLResourceIdentifier identifier,
  805                                        String encoding, Augmentations augs)
  806           throws XNIException {
  807   
  808           try {
  809               // Only report startEntity if this entity was actually read.
  810               if (augs != null && Boolean.TRUE.equals(augs.getItem(Constants.ENTITY_SKIPPED))) {
  811                   // report skipped entity to content handler
  812                   if (fContentHandler != null) {
  813                       fContentHandler.skippedEntity(name);
  814                   }
  815               }
  816               else {
  817                   // SAX2 extension
  818                   if (fLexicalHandler != null && fLexicalHandlerParameterEntities) {
  819                       fLexicalHandler.startEntity(name);
  820                   }
  821               }
  822           }
  823           catch (SAXException e) {
  824               throw new XNIException(e);
  825           }
  826   
  827       } // startParameterEntity(String,identifier,String,Augmentation)
  828   
  829       /**
  830        * This method notifies the end of an entity. The DTD has the pseudo-name
  831        * of "[dtd]" parameter entity names start with '%'; and general entity
  832        * names are just the entity name.
  833        * <p>
  834        * <strong>Note:</strong> Since the document is an entity, the handler
  835        * will be notified of the end of the document entity by calling the
  836        * endEntity method with the entity name "[xml]" <em>after</em> calling
  837        * the endDocument method. When exposing entity boundaries through the
  838        * SAX API, the document entity is never reported, however.
  839        * <p>
  840        * <strong>Note:</strong> This method is not called for entity references
  841        * appearing as part of attribute values.
  842        *
  843        * @param name The name of the parameter entity.
  844        * @param augs Additional information that may include infoset
  845        *                      augmentations.
  846        *
  847        * @throws XNIException Thrown by handler to signal an error.
  848        */
  849       public void endParameterEntity(String name, Augmentations augs) throws XNIException {
  850   
  851           try {
  852               // Only report endEntity if this entity was actually read.
  853               if (augs == null || !Boolean.TRUE.equals(augs.getItem(Constants.ENTITY_SKIPPED))) {
  854                   // SAX2 extension
  855                   if (fLexicalHandler != null && fLexicalHandlerParameterEntities) {
  856                       fLexicalHandler.endEntity(name);
  857                   }
  858               }
  859           }
  860           catch (SAXException e) {
  861               throw new XNIException(e);
  862           }
  863   
  864       } // endEntity(String)
  865   
  866       /**
  867        * An element declaration.
  868        *
  869        * @param name         The name of the element.
  870        * @param contentModel The element content model.
  871        *
  872        * @param augs Additional information that may include infoset
  873        *                      augmentations.
  874        *
  875        * @throws XNIException Thrown by handler to signal an error.
  876        */
  877       public void elementDecl(String name, String contentModel, Augmentations augs)
  878           throws XNIException {
  879   
  880           try {
  881               // SAX2 extension
  882               if (fDeclHandler != null) {
  883                   fDeclHandler.elementDecl(name, contentModel);
  884               }
  885           }
  886           catch (SAXException e) {
  887               throw new XNIException(e);
  888           }
  889   
  890       } // elementDecl(String,String, Augmentations)
  891   
  892       /**
  893        * An attribute declaration.
  894        *
  895        * @param elementName   The name of the element that this attribute
  896        *                      is associated with.
  897        * @param attributeName The name of the attribute.
  898        * @param type          The attribute type. This value will be one of
  899        *                      the following: "CDATA", "ENTITY", "ENTITIES",
  900        *                      "ENUMERATION", "ID", "IDREF", "IDREFS",
  901        *                      "NMTOKEN", "NMTOKENS", or "NOTATION".
  902        * @param enumeration   If the type has the value "ENUMERATION" or
  903        *                      "NOTATION", this array holds the allowed attribute
  904        *                      values; otherwise, this array is null.
  905        * @param defaultType   The attribute default type. This value will be
  906        *                      one of the following: "#FIXED", "#IMPLIED",
  907        *                      "#REQUIRED", or null.
  908        * @param defaultValue  The attribute default value, or null if no
  909        *                      default value is specified.
  910        *
  911        * @param nonNormalizedDefaultValue  The attribute default value with no normalization
  912        *                      performed, or null if no default value is specified.
  913        * @param augs Additional information that may include infoset
  914        *                      augmentations.
  915        *
  916        * @throws XNIException Thrown by handler to signal an error.
  917        */
  918       public void attributeDecl(String elementName, String attributeName,
  919                                 String type, String[] enumeration,
  920                                 String defaultType, XMLString defaultValue,
  921                                 XMLString nonNormalizedDefaultValue, Augmentations augs) throws XNIException {
  922   
  923           try {
  924               // SAX2 extension
  925               if (fDeclHandler != null) {
  926                   // used as a key to detect duplicate attribute definitions.
  927                   String elemAttr = new StringBuffer(elementName).append("<").append(attributeName).toString();
  928                   if(fDeclaredAttrs.get(elemAttr) != null) {
  929                       // we aren't permitted to return duplicate attribute definitions
  930                       return;
  931                   }
  932                   fDeclaredAttrs.put(elemAttr, Boolean.TRUE);
  933                   if (type.equals("NOTATION") ||
  934                       type.equals("ENUMERATION")) {
  935   
  936                       StringBuffer str = new StringBuffer();
  937                       if (type.equals("NOTATION")) {
  938                         str.append(type);
  939                         str.append(" (");
  940                       }
  941                       else {
  942                         str.append("(");
  943                       }
  944                       for (int i = 0; i < enumeration.length; i++) {
  945                           str.append(enumeration[i]);
  946                           if (i < enumeration.length - 1) {
  947                               str.append('|');
  948                           }
  949                       }
  950                       str.append(')');
  951                       type = str.toString();
  952                   }
  953                   String value = (defaultValue==null) ? null : defaultValue.toString();
  954                   fDeclHandler.attributeDecl(elementName, attributeName,
  955                                              type, defaultType, value);
  956               }
  957           }
  958           catch (SAXException e) {
  959               throw new XNIException(e);
  960           }
  961   
  962       } // attributeDecl(String,String,String,String[],String,XMLString, XMLString, Augmentations)
  963   
  964       /**
  965        * An internal entity declaration.
  966        *
  967        * @param name The name of the entity. Parameter entity names start with
  968        *             '%', whereas the name of a general entity is just the
  969        *             entity name.
  970        * @param text The value of the entity.
  971        * @param nonNormalizedText The non-normalized value of the entity. This
  972        *             value contains the same sequence of characters that was in
  973        *             the internal entity declaration, without any entity
  974        *             references expanded.
  975        *
  976        * @param augs Additional information that may include infoset
  977        *                      augmentations.
  978        *
  979        * @throws XNIException Thrown by handler to signal an error.
  980        */
  981       public void internalEntityDecl(String name, XMLString text,
  982                                      XMLString nonNormalizedText,
  983                                      Augmentations augs) throws XNIException {
  984   
  985           try {
  986               // SAX2 extensions
  987               if (fDeclHandler != null) {
  988                   fDeclHandler.internalEntityDecl(name, text.toString());
  989               }
  990           }
  991           catch (SAXException e) {
  992               throw new XNIException(e);
  993           }
  994   
  995       } // internalEntityDecl(String,XMLString,XMLString)
  996   
  997       /**
  998        * An external entity declaration.
  999        *
 1000        * @param name     The name of the entity. Parameter entity names start
 1001        *                 with '%', whereas the name of a general entity is just
 1002        *                 the entity name.
 1003        * @param identifier    An object containing all location information
 1004        *                      pertinent to this entity.
 1005        * @param augs Additional information that may include infoset
 1006        *                      augmentations.
 1007        *
 1008        * @throws XNIException Thrown by handler to signal an error.
 1009        */
 1010       public void externalEntityDecl(String name, XMLResourceIdentifier identifier,
 1011                                      Augmentations augs) throws XNIException {
 1012           try {
 1013               // SAX2 extension
 1014               if (fDeclHandler != null) {
 1015                   String publicId = identifier.getPublicId();
 1016                   String systemId = fResolveDTDURIs ?
 1017                       identifier.getExpandedSystemId() : identifier.getLiteralSystemId();
 1018                   fDeclHandler.externalEntityDecl(name, publicId, systemId);
 1019               }
 1020           }
 1021           catch (SAXException e) {
 1022               throw new XNIException(e);
 1023           }
 1024   
 1025       } // externalEntityDecl(String,,XMLResourceIdentifier, Augmentations)
 1026   
 1027       /**
 1028        * An unparsed entity declaration.
 1029        *
 1030        * @param name     The name of the entity.
 1031        * @param identifier    An object containing all location information
 1032        *                      pertinent to this entity.
 1033        * @param notation The name of the notation.
 1034        *
 1035        * @param augs Additional information that may include infoset
 1036        *                      augmentations.
 1037        *
 1038        * @throws XNIException Thrown by handler to signal an error.
 1039        */
 1040       public void unparsedEntityDecl(String name, XMLResourceIdentifier identifier,
 1041                                      String notation,
 1042                                      Augmentations augs) throws XNIException {
 1043           try {
 1044               // SAX2 extension
 1045               if (fDTDHandler != null) {
 1046                   String publicId = identifier.getPublicId();
 1047                   String systemId = fResolveDTDURIs ?
 1048                       identifier.getExpandedSystemId() : identifier.getLiteralSystemId();
 1049                   fDTDHandler.unparsedEntityDecl(name, publicId, systemId, notation);
 1050               }
 1051           }
 1052           catch (SAXException e) {
 1053               throw new XNIException(e);
 1054           }
 1055   
 1056       } // unparsedEntityDecl(String,XMLResourceIdentifier, String, Augmentations)
 1057   
 1058       /**
 1059        * A notation declaration
 1060        *
 1061        * @param name     The name of the notation.
 1062        * @param identifier    An object containing all location information
 1063        *                      pertinent to this notation.
 1064        * @param augs Additional information that may include infoset
 1065        *                      augmentations.
 1066        *
 1067        * @throws XNIException Thrown by handler to signal an error.
 1068        */
 1069       public void notationDecl(String name, XMLResourceIdentifier identifier,
 1070                                Augmentations augs) throws XNIException {
 1071           try {
 1072               // SAX1 and SAX2
 1073               if (fDTDHandler != null) {
 1074                   String publicId = identifier.getPublicId();
 1075                   String systemId = fResolveDTDURIs ?
 1076                       identifier.getExpandedSystemId() : identifier.getLiteralSystemId();
 1077                   fDTDHandler.notationDecl(name, publicId, systemId);
 1078               }
 1079           }
 1080           catch (SAXException e) {
 1081               throw new XNIException(e);
 1082           }
 1083   
 1084       } // notationDecl(String,XMLResourceIdentifier, Augmentations)
 1085   
 1086       /**
 1087        * The end of the DTD.
 1088        *
 1089        * @param augs Additional information that may include infoset
 1090        *                      augmentations.
 1091        *
 1092        * @throws XNIException Thrown by handler to signal an error.
 1093        */
 1094       public void endDTD(Augmentations augs) throws XNIException {
 1095           fInDTD = false;
 1096   
 1097           try {
 1098               // SAX2 extension
 1099               if (fLexicalHandler != null) {
 1100                   fLexicalHandler.endDTD();
 1101               }
 1102           }
 1103           catch (SAXException e) {
 1104               throw new XNIException(e);
 1105           }
 1106           if(fDeclaredAttrs != null) {
 1107               // help out the GC
 1108               fDeclaredAttrs.clear();
 1109           }
 1110   
 1111       } // endDTD()
 1112   
 1113       //
 1114       // Parser and XMLReader methods
 1115       //
 1116   
 1117       /**
 1118        * Parses the input source specified by the given system identifier.
 1119        * <p>
 1120        * This method is equivalent to the following:
 1121        * <pre>
 1122        *     parse(new InputSource(systemId));
 1123        * </pre>
 1124        *
 1125        * @param systemId The system identifier (URI).
 1126        *
 1127        * @exception org.xml.sax.SAXException Throws exception on SAX error.
 1128        * @exception java.io.IOException Throws exception on i/o error.
 1129        */
 1130       public void parse(String systemId) throws SAXException, IOException {
 1131   
 1132           // parse document
 1133           XMLInputSource source = new XMLInputSource(null, systemId, null);
 1134           try {
 1135               parse(source);
 1136           }
 1137   
 1138           // wrap XNI exceptions as SAX exceptions
 1139           catch (XMLParseException e) {
 1140               Exception ex = e.getException();
 1141               if (ex == null) {
 1142                   // must be a parser exception; mine it for locator info and throw
 1143                   // a SAXParseException
 1144                   LocatorImpl locatorImpl = new LocatorImpl(){
 1145                       public String getXMLVersion() {
 1146                           return fVersion;
 1147                       }
 1148                       // since XMLParseExceptions know nothing about encoding,
 1149                       // we cannot return anything meaningful in this context.
 1150                       // We *could* consult the LocatorProxy, but the
 1151                       // application can do this itself if it wishes to possibly
 1152                       // be mislead.
 1153                       public String getEncoding() {
 1154                           return null;
 1155                       }
 1156                   };
 1157                   locatorImpl.setPublicId(e.getPublicId());
 1158                   locatorImpl.setSystemId(e.getExpandedSystemId());
 1159                   locatorImpl.setLineNumber(e.getLineNumber());
 1160                   locatorImpl.setColumnNumber(e.getColumnNumber());
 1161                   throw new SAXParseException(e.getMessage(), locatorImpl);
 1162               }
 1163               if (ex instanceof SAXException) {
 1164                   // why did we create an XMLParseException?
 1165                   throw (SAXException)ex;
 1166               }
 1167               if (ex instanceof IOException) {
 1168                   throw (IOException)ex;
 1169               }
 1170               throw new SAXException(ex);
 1171           }
 1172           catch (XNIException e) {
 1173               Exception ex = e.getException();
 1174               if (ex == null) {
 1175                   throw new SAXException(e.getMessage());
 1176               }
 1177               if (ex instanceof SAXException) {
 1178                   throw (SAXException)ex;
 1179               }
 1180               if (ex instanceof IOException) {
 1181                   throw (IOException)ex;
 1182               }
 1183               throw new SAXException(ex);
 1184           }
 1185   
 1186       } // parse(String)
 1187   
 1188       /**
 1189        * parse
 1190        *
 1191        * @param inputSource
 1192        *
 1193        * @exception org.xml.sax.SAXException
 1194        * @exception java.io.IOException
 1195        */
 1196       public void parse(InputSource inputSource)
 1197           throws SAXException, IOException {
 1198   
 1199           // parse document
 1200           try {
 1201               XMLInputSource xmlInputSource =
 1202                   new XMLInputSource(inputSource.getPublicId(),
 1203                                      inputSource.getSystemId(),
 1204                                      null);
 1205               xmlInputSource.setByteStream(inputSource.getByteStream());
 1206               xmlInputSource.setCharacterStream(inputSource.getCharacterStream());
 1207               xmlInputSource.setEncoding(inputSource.getEncoding());
 1208               parse(xmlInputSource);
 1209           }
 1210   
 1211           // wrap XNI exceptions as SAX exceptions
 1212           catch (XMLParseException e) {
 1213               Exception ex = e.getException();
 1214               if (ex == null) {
 1215                   // must be a parser exception; mine it for locator info and throw
 1216                   // a SAXParseException
 1217                   LocatorImpl locatorImpl = new LocatorImpl() {
 1218                       public String getXMLVersion() {
 1219                           return fVersion;
 1220                       }
 1221                       // since XMLParseExceptions know nothing about encoding,
 1222                       // we cannot return anything meaningful in this context.
 1223                       // We *could* consult the LocatorProxy, but the
 1224                       // application can do this itself if it wishes to possibly
 1225                       // be mislead.
 1226                       public String getEncoding() {
 1227                           return null;
 1228                       }
 1229                   };
 1230                   locatorImpl.setPublicId(e.getPublicId());
 1231                   locatorImpl.setSystemId(e.getExpandedSystemId());
 1232                   locatorImpl.setLineNumber(e.getLineNumber());
 1233                   locatorImpl.setColumnNumber(e.getColumnNumber());
 1234                   throw new SAXParseException(e.getMessage(), locatorImpl);
 1235               }
 1236               if (ex instanceof SAXException) {
 1237                   // why did we create an XMLParseException?
 1238                   throw (SAXException)ex;
 1239               }
 1240               if (ex instanceof IOException) {
 1241                   throw (IOException)ex;
 1242               }
 1243               throw new SAXException(ex);
 1244           }
 1245           catch (XNIException e) {
 1246               Exception ex = e.getException();
 1247               if (ex == null) {
 1248                   throw new SAXException(e.getMessage());
 1249               }
 1250               if (ex instanceof SAXException) {
 1251                   throw (SAXException)ex;
 1252               }
 1253               if (ex instanceof IOException) {
 1254                   throw (IOException)ex;
 1255               }
 1256               throw new SAXException(ex);
 1257           }
 1258   
 1259       } // parse(InputSource)
 1260   
 1261       /**
 1262        * Sets the resolver used to resolve external entities. The EntityResolver
 1263        * interface supports resolution of public and system identifiers.
 1264        *
 1265        * @param resolver The new entity resolver. Passing a null value will
 1266        *                 uninstall the currently installed resolver.
 1267        */
 1268       public void setEntityResolver(EntityResolver resolver) {
 1269   
 1270           try {
 1271               XMLEntityResolver xer = (XMLEntityResolver) fConfiguration.getProperty(ENTITY_RESOLVER);
 1272               if (fUseEntityResolver2 && resolver instanceof EntityResolver2) {
 1273                   if (xer instanceof EntityResolver2Wrapper) {
 1274                       EntityResolver2Wrapper er2w = (EntityResolver2Wrapper) xer;
 1275                       er2w.setEntityResolver((EntityResolver2) resolver);
 1276                   }
 1277                   else {
 1278                       fConfiguration.setProperty(ENTITY_RESOLVER,
 1279                               new EntityResolver2Wrapper((EntityResolver2) resolver));
 1280                   }
 1281               }
 1282               else {
 1283                   if (xer instanceof EntityResolverWrapper) {
 1284                       EntityResolverWrapper erw = (EntityResolverWrapper) xer;
 1285                       erw.setEntityResolver(resolver);
 1286                   }
 1287                   else {
 1288                       fConfiguration.setProperty(ENTITY_RESOLVER,
 1289                               new EntityResolverWrapper(resolver));
 1290                   }
 1291               }
 1292           }
 1293           catch (XMLConfigurationException e) {
 1294               // do nothing
 1295           }
 1296   
 1297       } // setEntityResolver(EntityResolver)
 1298   
 1299       /**
 1300        * Return the current entity resolver.
 1301        *
 1302        * @return The current entity resolver, or null if none
 1303        *         has been registered.
 1304        * @see #setEntityResolver
 1305        */
 1306       public EntityResolver getEntityResolver() {
 1307   
 1308           EntityResolver entityResolver = null;
 1309           try {
 1310               XMLEntityResolver xmlEntityResolver =
 1311                   (XMLEntityResolver)fConfiguration.getProperty(ENTITY_RESOLVER);
 1312               if (xmlEntityResolver != null) {
 1313                   if (xmlEntityResolver instanceof EntityResolverWrapper) {
 1314                       entityResolver =
 1315                           ((EntityResolverWrapper) xmlEntityResolver).getEntityResolver();
 1316                   }
 1317                   else if (xmlEntityResolver instanceof EntityResolver2Wrapper) {
 1318                       entityResolver =
 1319                           ((EntityResolver2Wrapper) xmlEntityResolver).getEntityResolver();
 1320                   }
 1321               }
 1322           }
 1323           catch (XMLConfigurationException e) {
 1324               // do nothing
 1325           }
 1326           return entityResolver;
 1327   
 1328       } // getEntityResolver():EntityResolver
 1329   
 1330       /**
 1331        * Allow an application to register an error event handler.
 1332        *
 1333        * <p>If the application does not register an error handler, all
 1334        * error events reported by the SAX parser will be silently
 1335        * ignored; however, normal processing may not continue.  It is
 1336        * highly recommended that all SAX applications implement an
 1337        * error handler to avoid unexpected bugs.</p>
 1338        *
 1339        * <p>Applications may register a new or different handler in the
 1340        * middle of a parse, and the SAX parser must begin using the new
 1341        * handler immediately.</p>
 1342        *
 1343        * @param errorHandler The error handler.
 1344        * @see #getErrorHandler
 1345        */
 1346       public void setErrorHandler(ErrorHandler errorHandler) {
 1347   
 1348           try {
 1349               XMLErrorHandler xeh = (XMLErrorHandler) fConfiguration.getProperty(ERROR_HANDLER);
 1350               if (xeh instanceof ErrorHandlerWrapper) {
 1351                   ErrorHandlerWrapper ehw = (ErrorHandlerWrapper) xeh;
 1352                   ehw.setErrorHandler(errorHandler);
 1353               }
 1354               else {
 1355                   fConfiguration.setProperty(ERROR_HANDLER,
 1356                           new ErrorHandlerWrapper(errorHandler));
 1357               }
 1358           }
 1359           catch (XMLConfigurationException e) {
 1360               // do nothing
 1361           }
 1362   
 1363       } // setErrorHandler(ErrorHandler)
 1364   
 1365       /**
 1366        * Return the current error handler.
 1367        *
 1368        * @return The current error handler, or null if none
 1369        *         has been registered.
 1370        * @see #setErrorHandler
 1371        */
 1372       public ErrorHandler getErrorHandler() {
 1373   
 1374           ErrorHandler errorHandler = null;
 1375           try {
 1376               XMLErrorHandler xmlErrorHandler =
 1377                   (XMLErrorHandler)fConfiguration.getProperty(ERROR_HANDLER);
 1378               if (xmlErrorHandler != null &&
 1379                   xmlErrorHandler instanceof ErrorHandlerWrapper) {
 1380                   errorHandler = ((ErrorHandlerWrapper)xmlErrorHandler).getErrorHandler();
 1381               }
 1382           }
 1383           catch (XMLConfigurationException e) {
 1384               // do nothing
 1385           }
 1386           return errorHandler;
 1387   
 1388       } // getErrorHandler():ErrorHandler
 1389   
 1390       /**
 1391        * Set the locale to use for messages.
 1392        *
 1393        * @param locale The locale object to use for localization of messages.
 1394        *
 1395        * @exception SAXException An exception thrown if the parser does not
 1396        *                         support the specified locale.
 1397        *
 1398        * @see org.xml.sax.Parser
 1399        */
 1400       public void setLocale(Locale locale) throws SAXException {
 1401           //REVISIT:this methods is not part of SAX2 interfaces, we should throw exception
 1402           //if any application uses SAX2 and sets locale also. -nb
 1403           fConfiguration.setLocale(locale);
 1404   
 1405       } // setLocale(Locale)
 1406   
 1407       /**
 1408        * Allow an application to register a DTD event handler.
 1409        * <p>
 1410        * If the application does not register a DTD handler, all DTD
 1411        * events reported by the SAX parser will be silently ignored.
 1412        * <p>
 1413        * Applications may register a new or different handler in the
 1414        * middle of a parse, and the SAX parser must begin using the new
 1415        * handler immediately.
 1416        *
 1417        * @param dtdHandler The DTD handler.
 1418        *
 1419   
 1420        * @see #getDTDHandler
 1421        */
 1422       public void setDTDHandler(DTDHandler dtdHandler) {
 1423           fDTDHandler = dtdHandler;
 1424       } // setDTDHandler(DTDHandler)
 1425   
 1426       //
 1427       // Parser methods
 1428       //
 1429   
 1430       /**
 1431        * Allow an application to register a document event handler.
 1432        * <p>
 1433        * If the application does not register a document handler, all
 1434        * document events reported by the SAX parser will be silently
 1435        * ignored (this is the default behaviour implemented by
 1436        * HandlerBase).
 1437        * <p>
 1438        * Applications may register a new or different handler in the
 1439        * middle of a parse, and the SAX parser must begin using the new
 1440        * handler immediately.
 1441        *
 1442        * @param documentHandler The document handler.
 1443        */
 1444       public void setDocumentHandler(DocumentHandler documentHandler) {
 1445           fDocumentHandler = documentHandler;
 1446       } // setDocumentHandler(DocumentHandler)
 1447   
 1448       //
 1449       // XMLReader methods
 1450       //
 1451   
 1452       /**
 1453        * Allow an application to register a content event handler.
 1454        * <p>
 1455        * If the application does not register a content handler, all
 1456        * content events reported by the SAX parser will be silently
 1457        * ignored.
 1458        * <p>
 1459        * Applications may register a new or different handler in the
 1460        * middle of a parse, and the SAX parser must begin using the new
 1461        * handler immediately.
 1462        *
 1463        * @param contentHandler The content handler.
 1464        *
 1465        * @see #getContentHandler
 1466        */
 1467       public void setContentHandler(ContentHandler contentHandler) {
 1468           fContentHandler = contentHandler;
 1469       } // setContentHandler(ContentHandler)
 1470   
 1471       /**
 1472        * Return the current content handler.
 1473        *
 1474        * @return The current content handler, or null if none
 1475        *         has been registered.
 1476        *
 1477        * @see #setContentHandler
 1478        */
 1479       public ContentHandler getContentHandler() {
 1480           return fContentHandler;
 1481       } // getContentHandler():ContentHandler
 1482   
 1483       /**
 1484        * Return the current DTD handler.
 1485        *
 1486        * @return The current DTD handler, or null if none
 1487        *         has been registered.
 1488        * @see #setDTDHandler
 1489        */
 1490       public DTDHandler getDTDHandler() {
 1491           return fDTDHandler;
 1492       } // getDTDHandler():DTDHandler
 1493   
 1494       /**
 1495        * Set the state of any feature in a SAX2 parser.  The parser
 1496        * might not recognize the feature, and if it does recognize
 1497        * it, it might not be able to fulfill the request.
 1498        *
 1499        * @param featureId The unique identifier (URI) of the feature.
 1500        * @param state The requested state of the feature (true or false).
 1501        *
 1502        * @exception SAXNotRecognizedException If the
 1503        *            requested feature is not known.
 1504        * @exception SAXNotSupportedException If the
 1505        *            requested feature is known, but the requested
 1506        *            state is not supported.
 1507        */
 1508       public void setFeature(String featureId, boolean state)
 1509           throws SAXNotRecognizedException, SAXNotSupportedException {
 1510   
 1511           try {
 1512               //
 1513               // SAX2 Features
 1514               //
 1515   
 1516               if (featureId.startsWith(Constants.SAX_FEATURE_PREFIX)) {
 1517                   final int suffixLength = featureId.length() - Constants.SAX_FEATURE_PREFIX.length();
 1518   
 1519                   // http://xml.org/sax/features/namespaces
 1520                   if (suffixLength == Constants.NAMESPACES_FEATURE.length() &&
 1521                       featureId.endsWith(Constants.NAMESPACES_FEATURE)) {
 1522                       fConfiguration.setFeature(featureId, state);
 1523                       fNamespaces = state;
 1524                       return;
 1525                   }
 1526   
 1527                   // http://xml.org/sax/features/namespace-prefixes
 1528                   //   controls the reporting of raw prefixed names and Namespace
 1529                   //   declarations (xmlns* attributes): when this feature is false
 1530                   //   (the default), raw prefixed names may optionally be reported,
 1531                   //   and xmlns* attributes must not be reported.
 1532                   //
 1533                   if (suffixLength == Constants.NAMESPACE_PREFIXES_FEATURE.length() &&
 1534                       featureId.endsWith(Constants.NAMESPACE_PREFIXES_FEATURE)) {
 1535                       fConfiguration.setFeature(featureId, state);
 1536                       fNamespacePrefixes = state;
 1537                       return;
 1538                   }
 1539   
 1540                   // http://xml.org/sax/features/string-interning
 1541                   //   controls the use of java.lang.String#intern() for strings
 1542                   //   passed to SAX handlers.
 1543                   //
 1544                   if (suffixLength == Constants.STRING_INTERNING_FEATURE.length() &&
 1545                       featureId.endsWith(Constants.STRING_INTERNING_FEATURE)) {
 1546                       if (!state) {
 1547                           throw new SAXNotSupportedException(
 1548                               SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 1549                               "false-not-supported", new Object [] {featureId}));
 1550                       }
 1551                       return;
 1552                   }
 1553   
 1554                   // http://xml.org/sax/features/lexical-handler/parameter-entities
 1555                   //   controls whether the beginning and end of parameter entities
 1556                   //   will be reported to the LexicalHandler.
 1557                   //
 1558                   if (suffixLength == Constants.LEXICAL_HANDLER_PARAMETER_ENTITIES_FEATURE.length() &&
 1559                       featureId.endsWith(Constants.LEXICAL_HANDLER_PARAMETER_ENTITIES_FEATURE)) {
 1560                       fLexicalHandlerParameterEntities = state;
 1561                       return;
 1562                   }
 1563   
 1564                   // http://xml.org/sax/features/resolve-dtd-uris
 1565                   //   controls whether system identifiers will be absolutized relative to
 1566                   //   their base URIs before reporting.
 1567                   //
 1568                   if (suffixLength == Constants.RESOLVE_DTD_URIS_FEATURE.length() &&
 1569                       featureId.endsWith(Constants.RESOLVE_DTD_URIS_FEATURE)) {
 1570                       fResolveDTDURIs = state;
 1571                       return;
 1572                   }
 1573   
 1574                   // http://xml.org/sax/features/unicode-normalization-checking
 1575                   //   controls whether Unicode normalization checking is performed
 1576                   //   as per Appendix B of the XML 1.1 specification
 1577                   //
 1578                   if (suffixLength == Constants.UNICODE_NORMALIZATION_CHECKING_FEATURE.length() &&
 1579                       featureId.endsWith(Constants.UNICODE_NORMALIZATION_CHECKING_FEATURE)) {
 1580                       // REVISIT: Allow this feature to be set once Unicode normalization
 1581                       // checking is supported -- mrglavas.
 1582                       if (state) {
 1583                           throw new SAXNotSupportedException(
 1584                               SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 1585                               "true-not-supported", new Object [] {featureId}));
 1586                       }
 1587                       return;
 1588                   }
 1589   
 1590                   // http://xml.org/sax/features/xmlns-uris
 1591                   //   controls whether the parser reports that namespace declaration
 1592                   //   attributes as being in the namespace: http://www.w3.org/2000/xmlns/
 1593                   //
 1594                   if (suffixLength == Constants.XMLNS_URIS_FEATURE.length() &&
 1595                       featureId.endsWith(Constants.XMLNS_URIS_FEATURE)) {
 1596                       fXMLNSURIs = state;
 1597                       return;
 1598                   }
 1599   
 1600                   // http://xml.org/sax/features/use-entity-resolver2
 1601                   //   controls whether the methods of an object implementing
 1602                   //   org.xml.sax.ext.EntityResolver2 will be used by the parser.
 1603                   //
 1604                   if (suffixLength == Constants.USE_ENTITY_RESOLVER2_FEATURE.length() &&
 1605                       featureId.endsWith(Constants.USE_ENTITY_RESOLVER2_FEATURE)) {
 1606                       if (state != fUseEntityResolver2) {
 1607                           fUseEntityResolver2 = state;
 1608                           // Refresh EntityResolver wrapper.
 1609                           setEntityResolver(getEntityResolver());
 1610                       }
 1611                       return;
 1612                   }
 1613   
 1614                   //
 1615                   // Read only features.
 1616                   //
 1617   
 1618                   // http://xml.org/sax/features/is-standalone
 1619                   //   reports whether the document specified a standalone document declaration.
 1620                   // http://xml.org/sax/features/use-attributes2
 1621                   //   reports whether Attributes objects passed to startElement also implement
 1622                   //   the org.xml.sax.ext.Attributes2 interface.
 1623                   // http://xml.org/sax/features/use-locator2
 1624                   //   reports whether Locator objects passed to setDocumentLocator also implement
 1625                   //   the org.xml.sax.ext.Locator2 interface.
 1626                   // http://xml.org/sax/features/xml-1.1
 1627                   //   reports whether the parser supports both XML 1.1 and XML 1.0.
 1628                   if ((suffixLength == Constants.IS_STANDALONE_FEATURE.length() &&
 1629                       featureId.endsWith(Constants.IS_STANDALONE_FEATURE)) ||
 1630                       (suffixLength == Constants.USE_ATTRIBUTES2_FEATURE.length() &&
 1631                       featureId.endsWith(Constants.USE_ATTRIBUTES2_FEATURE)) ||
 1632                       (suffixLength == Constants.USE_LOCATOR2_FEATURE.length() &&
 1633                       featureId.endsWith(Constants.USE_LOCATOR2_FEATURE)) ||
 1634                       (suffixLength == Constants.XML_11_FEATURE.length() &&
 1635                       featureId.endsWith(Constants.XML_11_FEATURE))) {
 1636                       throw new SAXNotSupportedException(
 1637                           SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 1638                           "feature-read-only", new Object [] {featureId}));
 1639                   }
 1640   
 1641   
 1642                   //
 1643                   // Drop through and perform default processing
 1644                   //
 1645               }
 1646   
 1647               //
 1648               // Xerces Features
 1649               //
 1650   
 1651               /*
 1652               else if (featureId.startsWith(XERCES_FEATURES_PREFIX)) {
 1653                   String feature = featureId.substring(XERCES_FEATURES_PREFIX.length());
 1654                   //
 1655                   // Drop through and perform default processing
 1656                   //
 1657               }
 1658               */
 1659   
 1660               //
 1661               // Default handling
 1662               //
 1663   
 1664               fConfiguration.setFeature(featureId, state);
 1665           }
 1666           catch (XMLConfigurationException e) {
 1667               String identifier = e.getIdentifier();
 1668               if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) {
 1669                   throw new SAXNotRecognizedException(
 1670                       SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 1671                       "feature-not-recognized", new Object [] {identifier}));
 1672               }
 1673               else {
 1674                   throw new SAXNotSupportedException(
 1675                       SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 1676                       "feature-not-supported", new Object [] {identifier}));
 1677               }
 1678           }
 1679   
 1680       } // setFeature(String,boolean)
 1681   
 1682       /**
 1683        * Query the state of a feature.
 1684        *
 1685        * Query the current state of any feature in a SAX2 parser.  The
 1686        * parser might not recognize the feature.
 1687        *
 1688        * @param featureId The unique identifier (URI) of the feature
 1689        *                  being set.
 1690        * @return The current state of the feature.
 1691        * @exception org.xml.sax.SAXNotRecognizedException If the
 1692        *            requested feature is not known.
 1693        * @exception SAXNotSupportedException If the
 1694        *            requested feature is known but not supported.
 1695        */
 1696       public boolean getFeature(String featureId)
 1697           throws SAXNotRecognizedException, SAXNotSupportedException {
 1698   
 1699           try {
 1700               //
 1701               // SAX2 Features
 1702               //
 1703   
 1704               if (featureId.startsWith(Constants.SAX_FEATURE_PREFIX)) {
 1705                   final int suffixLength = featureId.length() - Constants.SAX_FEATURE_PREFIX.length();
 1706   
 1707                   // http://xml.org/sax/features/namespace-prefixes
 1708                   //   controls the reporting of raw prefixed names and Namespace
 1709                   //   declarations (xmlns* attributes): when this feature is false
 1710                   //   (the default), raw prefixed names may optionally be reported,
 1711                   //   and xmlns* attributes must not be reported.
 1712                   //
 1713                   if (suffixLength == Constants.NAMESPACE_PREFIXES_FEATURE.length() &&
 1714                       featureId.endsWith(Constants.NAMESPACE_PREFIXES_FEATURE)) {
 1715                       boolean state = fConfiguration.getFeature(featureId);
 1716                       return state;
 1717                   }
 1718                   // http://xml.org/sax/features/string-interning
 1719                   //   controls the use of java.lang.String#intern() for strings
 1720                   //   passed to SAX handlers.
 1721                   //
 1722                   if (suffixLength == Constants.STRING_INTERNING_FEATURE.length() &&
 1723                       featureId.endsWith(Constants.STRING_INTERNING_FEATURE)) {
 1724                       return true;
 1725                   }
 1726   
 1727                   // http://xml.org/sax/features/is-standalone
 1728                   //   reports whether the document specified a standalone document declaration.
 1729                   //
 1730                   if (suffixLength == Constants.IS_STANDALONE_FEATURE.length() &&
 1731                       featureId.endsWith(Constants.IS_STANDALONE_FEATURE)) {
 1732                       return fStandalone;
 1733                   }
 1734   
 1735                   // http://xml.org/sax/features/xml-1.1
 1736                   //   reports whether the parser supports both XML 1.1 and XML 1.0.
 1737                   //
 1738                   if (suffixLength == Constants.XML_11_FEATURE.length() &&
 1739                       featureId.endsWith(Constants.XML_11_FEATURE)) {
 1740                       return (fConfiguration instanceof XML11Configurable);
 1741                   }
 1742   
 1743                   // http://xml.org/sax/features/lexical-handler/parameter-entities
 1744                   //   controls whether the beginning and end of parameter entities
 1745                   //   will be reported to the LexicalHandler.
 1746                   //
 1747                   if (suffixLength == Constants.LEXICAL_HANDLER_PARAMETER_ENTITIES_FEATURE.length() &&
 1748                       featureId.endsWith(Constants.LEXICAL_HANDLER_PARAMETER_ENTITIES_FEATURE)) {
 1749                       return fLexicalHandlerParameterEntities;
 1750                   }
 1751   
 1752                   // http://xml.org/sax/features/resolve-dtd-uris
 1753                   //   controls whether system identifiers will be absolutized relative to
 1754                   //   their base URIs before reporting.
 1755                   if (suffixLength == Constants.RESOLVE_DTD_URIS_FEATURE.length() &&
 1756                       featureId.endsWith(Constants.RESOLVE_DTD_URIS_FEATURE)) {
 1757                       return fResolveDTDURIs;
 1758                   }
 1759   
 1760                   // http://xml.org/sax/features/xmlns-uris
 1761                   //   controls whether the parser reports that namespace declaration
 1762                   //   attributes as being in the namespace: http://www.w3.org/2000/xmlns/
 1763                   //
 1764                   if (suffixLength == Constants.XMLNS_URIS_FEATURE.length() &&
 1765                       featureId.endsWith(Constants.XMLNS_URIS_FEATURE)) {
 1766                       return fXMLNSURIs;
 1767                   }
 1768   
 1769                   // http://xml.org/sax/features/unicode-normalization-checking
 1770                   //   controls whether Unicode normalization checking is performed
 1771                   //   as per Appendix B of the XML 1.1 specification
 1772                   //
 1773                   if (suffixLength == Constants.UNICODE_NORMALIZATION_CHECKING_FEATURE.length() &&
 1774                       featureId.endsWith(Constants.UNICODE_NORMALIZATION_CHECKING_FEATURE)) {
 1775                       // REVISIT: Allow this feature to be set once Unicode normalization
 1776                       // checking is supported -- mrglavas.
 1777                       return false;
 1778                   }
 1779   
 1780                   // http://xml.org/sax/features/use-entity-resolver2
 1781                   //   controls whether the methods of an object implementing
 1782                   //   org.xml.sax.ext.EntityResolver2 will be used by the parser.
 1783                   //
 1784                   if (suffixLength == Constants.USE_ENTITY_RESOLVER2_FEATURE.length() &&
 1785                       featureId.endsWith(Constants.USE_ENTITY_RESOLVER2_FEATURE)) {
 1786                       return fUseEntityResolver2;
 1787                   }
 1788   
 1789                   // http://xml.org/sax/features/use-attributes2
 1790                   //   reports whether Attributes objects passed to startElement also implement
 1791                   //   the org.xml.sax.ext.Attributes2 interface.
 1792                   // http://xml.org/sax/features/use-locator2
 1793                   //   reports whether Locator objects passed to setDocumentLocator also implement
 1794                   //   the org.xml.sax.ext.Locator2 interface.
 1795                   //
 1796                   if ((suffixLength == Constants.USE_ATTRIBUTES2_FEATURE.length() &&
 1797                       featureId.endsWith(Constants.USE_ATTRIBUTES2_FEATURE)) ||
 1798                       (suffixLength == Constants.USE_LOCATOR2_FEATURE.length() &&
 1799                       featureId.endsWith(Constants.USE_LOCATOR2_FEATURE))) {
 1800                       return true;
 1801                   }
 1802   
 1803   
 1804                   //
 1805                   // Drop through and perform default processing
 1806                   //
 1807               }
 1808   
 1809               //
 1810               // Xerces Features
 1811               //
 1812   
 1813               /*
 1814               else if (featureId.startsWith(XERCES_FEATURES_PREFIX)) {
 1815                   //
 1816                   // Drop through and perform default processing
 1817                   //
 1818               }
 1819               */
 1820   
 1821               return fConfiguration.getFeature(featureId);
 1822           }
 1823           catch (XMLConfigurationException e) {
 1824               String identifier = e.getIdentifier();
 1825               if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) {
 1826                   throw new SAXNotRecognizedException(
 1827                       SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 1828                       "feature-not-recognized", new Object [] {identifier}));
 1829               }
 1830               else {
 1831                   throw new SAXNotSupportedException(
 1832                       SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 1833                       "feature-not-supported", new Object [] {identifier}));
 1834               }
 1835           }
 1836   
 1837       } // getFeature(String):boolean
 1838   
 1839       /**
 1840        * Set the value of any property in a SAX2 parser.  The parser
 1841        * might not recognize the property, and if it does recognize
 1842        * it, it might not support the requested value.
 1843        *
 1844        * @param propertyId The unique identifier (URI) of the property
 1845        *                   being set.
 1846        * @param value The value to which the property is being set.
 1847        *
 1848        * @exception SAXNotRecognizedException If the
 1849        *            requested property is not known.
 1850        * @exception SAXNotSupportedException If the
 1851        *            requested property is known, but the requested
 1852        *            value is not supported.
 1853        */
 1854       public void setProperty(String propertyId, Object value)
 1855           throws SAXNotRecognizedException, SAXNotSupportedException {
 1856   
 1857           try {
 1858               //
 1859               // SAX2 core properties
 1860               //
 1861   
 1862               if (propertyId.startsWith(Constants.SAX_PROPERTY_PREFIX)) {
 1863                   final int suffixLength = propertyId.length() - Constants.SAX_PROPERTY_PREFIX.length();
 1864   
 1865                   //
 1866                   // http://xml.org/sax/properties/lexical-handler
 1867                   // Value type: org.xml.sax.ext.LexicalHandler
 1868                   // Access: read/write, pre-parse only
 1869                   //   Set the lexical event handler.
 1870                   //
 1871                   if (suffixLength == Constants.LEXICAL_HANDLER_PROPERTY.length() &&
 1872                       propertyId.endsWith(Constants.LEXICAL_HANDLER_PROPERTY)) {
 1873                       try {
 1874                           setLexicalHandler((LexicalHandler)value);
 1875                       }
 1876                       catch (ClassCastException e) {
 1877                           throw new SAXNotSupportedException(
 1878                               SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 1879                               "incompatible-class", new Object [] {propertyId, "org.xml.sax.ext.LexicalHandler"}));
 1880                       }
 1881                       return;
 1882                   }
 1883                   //
 1884                   // http://xml.org/sax/properties/declaration-handler
 1885                   // Value type: org.xml.sax.ext.DeclHandler
 1886                   // Access: read/write, pre-parse only
 1887                   //   Set the DTD declaration event handler.
 1888                   //
 1889                   if (suffixLength == Constants.DECLARATION_HANDLER_PROPERTY.length() &&
 1890                       propertyId.endsWith(Constants.DECLARATION_HANDLER_PROPERTY)) {
 1891                       try {
 1892                           setDeclHandler((DeclHandler)value);
 1893                       }
 1894                       catch (ClassCastException e) {
 1895                           throw new SAXNotSupportedException(
 1896                               SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 1897                               "incompatible-class", new Object [] {propertyId, "org.xml.sax.ext.DeclHandler"}));
 1898                       }
 1899                       return;
 1900                   }
 1901                   //
 1902                   // http://xml.org/sax/properties/dom-node
 1903                   // Value type: DOM Node
 1904                   // Access: read-only
 1905                   //   Get the DOM node currently being visited, if the SAX parser is
 1906                   //   iterating over a DOM tree.  If the parser recognises and
 1907                   //   supports this property but is not currently visiting a DOM
 1908                   //   node, it should return null (this is a good way to check for
 1909                   //   availability before the parse begins).
 1910                   // http://xml.org/sax/properties/document-xml-version
 1911                   // Value type: java.lang.String
 1912                   // Access: read-only
 1913                   //   The literal string describing the actual XML version of the document.
 1914                   //
 1915                   if ((suffixLength == Constants.DOM_NODE_PROPERTY.length() &&
 1916                       propertyId.endsWith(Constants.DOM_NODE_PROPERTY)) ||
 1917                       (suffixLength == Constants.DOCUMENT_XML_VERSION_PROPERTY.length() &&
 1918                       propertyId.endsWith(Constants.DOCUMENT_XML_VERSION_PROPERTY))) {
 1919                       throw new SAXNotSupportedException(
 1920                           SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 1921                           "property-read-only", new Object [] {propertyId}));
 1922                   }
 1923                   //
 1924                   // Drop through and perform default processing
 1925                   //
 1926               }
 1927   
 1928               //
 1929               // Xerces Properties
 1930               //
 1931   
 1932               /*
 1933               else if (propertyId.startsWith(XERCES_PROPERTIES_PREFIX)) {
 1934                   //
 1935                   // Drop through and perform default processing
 1936                   //
 1937               }
 1938               */
 1939   
 1940               //
 1941               // Perform default processing
 1942               //
 1943   
 1944               fConfiguration.setProperty(propertyId, value);
 1945           }
 1946           catch (XMLConfigurationException e) {
 1947               String identifier = e.getIdentifier();
 1948               if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) {
 1949                   throw new SAXNotRecognizedException(
 1950                       SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 1951                       "property-not-recognized", new Object [] {identifier}));
 1952               }
 1953               else {
 1954                   throw new SAXNotSupportedException(
 1955                       SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 1956                       "property-not-supported", new Object [] {identifier}));
 1957               }
 1958           }
 1959   
 1960       } // setProperty(String,Object)
 1961   
 1962       /**
 1963        * Query the value of a property.
 1964        *
 1965        * Return the current value of a property in a SAX2 parser.
 1966        * The parser might not recognize the property.
 1967        *
 1968        * @param propertyId The unique identifier (URI) of the property
 1969        *                   being set.
 1970        * @return The current value of the property.
 1971        * @exception org.xml.sax.SAXNotRecognizedException If the
 1972        *            requested property is not known.
 1973        * @exception SAXNotSupportedException If the
 1974        *            requested property is known but not supported.
 1975        */
 1976       public Object getProperty(String propertyId)
 1977           throws SAXNotRecognizedException, SAXNotSupportedException {
 1978   
 1979           try {
 1980               //
 1981               // SAX2 core properties
 1982               //
 1983   
 1984               if (propertyId.startsWith(Constants.SAX_PROPERTY_PREFIX)) {
 1985                   final int suffixLength = propertyId.length() - Constants.SAX_PROPERTY_PREFIX.length();
 1986   
 1987                   //
 1988                   // http://xml.org/sax/properties/document-xml-version
 1989                   // Value type: java.lang.String
 1990                   // Access: read-only
 1991                   //   The literal string describing the actual XML version of the document.
 1992                   //
 1993                   if (suffixLength == Constants.DOCUMENT_XML_VERSION_PROPERTY.length() &&
 1994                       propertyId.endsWith(Constants.DOCUMENT_XML_VERSION_PROPERTY)) {
 1995                       return fVersion;
 1996                   }
 1997   
 1998                   //
 1999                   // http://xml.org/sax/properties/lexical-handler
 2000                   // Value type: org.xml.sax.ext.LexicalHandler
 2001                   // Access: read/write, pre-parse only
 2002                   //   Set the lexical event handler.
 2003                   //
 2004                   if (suffixLength == Constants.LEXICAL_HANDLER_PROPERTY.length() &&
 2005                       propertyId.endsWith(Constants.LEXICAL_HANDLER_PROPERTY)) {
 2006                       return getLexicalHandler();
 2007                   }
 2008                   //
 2009                   // http://xml.org/sax/properties/declaration-handler
 2010                   // Value type: org.xml.sax.ext.DeclHandler
 2011                   // Access: read/write, pre-parse only
 2012                   //   Set the DTD declaration event handler.
 2013                   //
 2014                   if (suffixLength == Constants.DECLARATION_HANDLER_PROPERTY.length() &&
 2015                       propertyId.endsWith(Constants.DECLARATION_HANDLER_PROPERTY)) {
 2016                       return getDeclHandler();
 2017                   }
 2018   
 2019                   //
 2020                   // http://xml.org/sax/properties/dom-node
 2021                   // Value type: DOM Node
 2022                   // Access: read-only
 2023                   //   Get the DOM node currently being visited, if the SAX parser is
 2024                   //   iterating over a DOM tree.  If the parser recognises and
 2025                   //   supports this property but is not currently visiting a DOM
 2026                   //   node, it should return null (this is a good way to check for
 2027                   //   availability before the parse begins).
 2028                   //
 2029                   if (suffixLength == Constants.DOM_NODE_PROPERTY.length() &&
 2030                       propertyId.endsWith(Constants.DOM_NODE_PROPERTY)) {
 2031                       // we are not iterating a DOM tree
 2032                       throw new SAXNotSupportedException(
 2033                           SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 2034                           "dom-node-read-not-supported", null));
 2035                   }
 2036   
 2037                   //
 2038                   // Drop through and perform default processing
 2039                   //
 2040               }
 2041   
 2042               //
 2043               // Xerces properties
 2044               //
 2045   
 2046               /*
 2047               else if (propertyId.startsWith(XERCES_PROPERTIES_PREFIX)) {
 2048                   //
 2049                   // Drop through and perform default processing
 2050                   //
 2051               }
 2052               */
 2053   
 2054               //
 2055               // Perform default processing
 2056               //
 2057   
 2058               return fConfiguration.getProperty(propertyId);
 2059           }
 2060           catch (XMLConfigurationException e) {
 2061               String identifier = e.getIdentifier();
 2062               if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) {
 2063                   throw new SAXNotRecognizedException(
 2064                       SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 2065                       "property-not-recognized", new Object [] {identifier}));
 2066               }
 2067               else {
 2068                   throw new SAXNotSupportedException(
 2069                       SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 2070                       "property-not-supported", new Object [] {identifier}));
 2071               }
 2072           }
 2073   
 2074       } // getProperty(String):Object
 2075   
 2076       //
 2077       // Protected methods
 2078       //
 2079   
 2080       // SAX2 core properties
 2081   
 2082       /**
 2083        * Set the DTD declaration event handler.
 2084        * <p>
 2085        * This method is the equivalent to the property:
 2086        * <pre>
 2087        * http://xml.org/sax/properties/declaration-handler
 2088        * </pre>
 2089        *
 2090        * @param handler The new handler.
 2091        *
 2092        * @see #getDeclHandler
 2093        * @see #setProperty
 2094        */
 2095       protected void setDeclHandler(DeclHandler handler)
 2096           throws SAXNotRecognizedException, SAXNotSupportedException {
 2097   
 2098           if (fParseInProgress) {
 2099               throw new SAXNotSupportedException(
 2100                   SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 2101                   "property-not-parsing-supported",
 2102                   new Object [] {"http://xml.org/sax/properties/declaration-handler"}));
 2103           }
 2104           fDeclHandler = handler;
 2105   
 2106       } // setDeclHandler(DeclHandler)
 2107   
 2108       /**
 2109        * Returns the DTD declaration event handler.
 2110        *
 2111        * @see #setDeclHandler
 2112        */
 2113       protected DeclHandler getDeclHandler()
 2114           throws SAXNotRecognizedException, SAXNotSupportedException {
 2115           return fDeclHandler;
 2116       } // getDeclHandler():DeclHandler
 2117   
 2118       /**
 2119        * Set the lexical event handler.
 2120        * <p>
 2121        * This method is the equivalent to the property:
 2122        * <pre>
 2123        * http://xml.org/sax/properties/lexical-handler
 2124        * </pre>
 2125        *
 2126        * @param handler lexical event handler
 2127        *
 2128        * @see #getLexicalHandler
 2129        * @see #setProperty
 2130        */
 2131       protected void setLexicalHandler(LexicalHandler handler)
 2132           throws SAXNotRecognizedException, SAXNotSupportedException {
 2133   
 2134           if (fParseInProgress) {
 2135               throw new SAXNotSupportedException(
 2136                   SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 2137                   "property-not-parsing-supported",
 2138                   new Object [] {"http://xml.org/sax/properties/lexical-handler"}));
 2139           }
 2140           fLexicalHandler = handler;
 2141   
 2142       } // setLexicalHandler(LexicalHandler)
 2143   
 2144       /**
 2145        * Returns the lexical handler.
 2146        *
 2147        * @see #setLexicalHandler
 2148        */
 2149       protected LexicalHandler getLexicalHandler()
 2150           throws SAXNotRecognizedException, SAXNotSupportedException {
 2151           return fLexicalHandler;
 2152       } // getLexicalHandler():LexicalHandler
 2153   
 2154       /**
 2155        * Send startPrefixMapping events
 2156        */
 2157       protected final void startNamespaceMapping() throws SAXException{
 2158           int count = fNamespaceContext.getDeclaredPrefixCount();
 2159           if (count > 0) {
 2160               String prefix = null;
 2161               String uri = null;
 2162               for (int i = 0; i < count; i++) {
 2163                   prefix = fNamespaceContext.getDeclaredPrefixAt(i);
 2164                   uri = fNamespaceContext.getURI(prefix);
 2165                   fContentHandler.startPrefixMapping(prefix,
 2166                       (uri == null) ? "" : uri);
 2167               }
 2168           }
 2169       }
 2170   
 2171       /**
 2172        * Send endPrefixMapping events
 2173        */
 2174       protected final void endNamespaceMapping() throws SAXException {
 2175           int count = fNamespaceContext.getDeclaredPrefixCount();
 2176           if (count > 0) {
 2177               for (int i = 0; i < count; i++) {
 2178                   fContentHandler.endPrefixMapping(fNamespaceContext.getDeclaredPrefixAt(i));
 2179               }
 2180           }
 2181       }
 2182   
 2183       //
 2184       // XMLDocumentParser methods
 2185       //
 2186   
 2187       /**
 2188        * Reset all components before parsing.
 2189        *
 2190        * @throws XNIException Thrown if an error occurs during initialization.
 2191        */
 2192       public void reset() throws XNIException {
 2193           super.reset();
 2194   
 2195           // reset state
 2196           fInDTD = false;
 2197           fVersion = "1.0";
 2198           fStandalone = false;
 2199   
 2200           // features
 2201           fNamespaces = fConfiguration.getFeature(NAMESPACES);
 2202           fNamespacePrefixes = fConfiguration.getFeature(NAMESPACE_PREFIXES);
 2203           fAugmentations = null;
 2204           fDeclaredAttrs = null;
 2205   
 2206       } // reset()
 2207   
 2208       //
 2209       // Classes
 2210       //
 2211   
 2212       protected class LocatorProxy
 2213           implements Locator2 {
 2214   
 2215           //
 2216           // Data
 2217           //
 2218   
 2219           /** XML locator. */
 2220           protected XMLLocator fLocator;
 2221   
 2222           //
 2223           // Constructors
 2224           //
 2225   
 2226           /** Constructs an XML locator proxy. */
 2227           public LocatorProxy(XMLLocator locator) {
 2228               fLocator = locator;
 2229           }
 2230   
 2231           //
 2232           // Locator methods
 2233           //
 2234   
 2235           /** Public identifier. */
 2236           public String getPublicId() {
 2237               return fLocator.getPublicId();
 2238           }
 2239   
 2240           /** System identifier. */
 2241           public String getSystemId() {
 2242               return fLocator.getExpandedSystemId();
 2243           }
 2244           /** Line number. */
 2245           public int getLineNumber() {
 2246               return fLocator.getLineNumber();
 2247           }
 2248   
 2249           /** Column number. */
 2250           public int getColumnNumber() {
 2251               return fLocator.getColumnNumber();
 2252           }
 2253   
 2254           // Locator2 methods
 2255           public String getXMLVersion() {
 2256               return fLocator.getXMLVersion();
 2257           }
 2258   
 2259           public String getEncoding() {
 2260               return fLocator.getEncoding();
 2261           }
 2262   
 2263       } // class LocatorProxy
 2264   
 2265       protected static final class AttributesProxy
 2266           implements AttributeList, Attributes2 {
 2267   
 2268           //
 2269           // Data
 2270           //
 2271   
 2272           /** XML attributes. */
 2273           protected XMLAttributes fAttributes;
 2274   
 2275           //
 2276           // Public methods
 2277           //
 2278   
 2279           /** Sets the XML attributes. */
 2280           public void setAttributes(XMLAttributes attributes) {
 2281               fAttributes = attributes;
 2282           } // setAttributes(XMLAttributes)
 2283   
 2284           public int getLength() {
 2285               return fAttributes.getLength();
 2286           }
 2287   
 2288           public String getName(int i) {
 2289               return fAttributes.getQName(i);
 2290           }
 2291   
 2292           public String getQName(int index) {
 2293               return fAttributes.getQName(index);
 2294           }
 2295   
 2296           public String getURI(int index) {
 2297               // REVISIT: this hides the fact that internally we use
 2298               //          null instead of empty string
 2299               //          SAX requires URI to be a string or an empty string
 2300               String uri= fAttributes.getURI(index);
 2301               return uri != null ? uri : "";
 2302           }
 2303   
 2304           public String getLocalName(int index) {
 2305               return fAttributes.getLocalName(index);
 2306           }
 2307   
 2308           public String getType(int i) {
 2309               return fAttributes.getType(i);
 2310           }
 2311   
 2312           public String getType(String name) {
 2313               return fAttributes.getType(name);
 2314           }
 2315   
 2316           public String getType(String uri, String localName) {
 2317               return uri.equals("") ? fAttributes.getType(null, localName) :
 2318                                       fAttributes.getType(uri, localName);
 2319           }
 2320   
 2321           public String getValue(int i) {
 2322               return fAttributes.getValue(i);
 2323           }
 2324   
 2325           public String getValue(String name) {
 2326               return fAttributes.getValue(name);
 2327           }
 2328   
 2329           public String getValue(String uri, String localName) {
 2330