1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  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 com.sun.org.apache.xerces.internal.dom.AttrImpl;
  24 import com.sun.org.apache.xerces.internal.dom.CoreDocumentImpl;
  25 import com.sun.org.apache.xerces.internal.dom.DOMErrorImpl;
  26 import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter;
  27 import com.sun.org.apache.xerces.internal.dom.DeferredDocumentImpl;
  28 import com.sun.org.apache.xerces.internal.dom.DocumentImpl;
  29 import com.sun.org.apache.xerces.internal.dom.DocumentTypeImpl;
  30 import com.sun.org.apache.xerces.internal.dom.ElementDefinitionImpl;
  31 import com.sun.org.apache.xerces.internal.dom.ElementImpl;
  32 import com.sun.org.apache.xerces.internal.dom.ElementNSImpl;
  33 import com.sun.org.apache.xerces.internal.dom.EntityImpl;
  34 import com.sun.org.apache.xerces.internal.dom.EntityReferenceImpl;
  35 import com.sun.org.apache.xerces.internal.dom.NodeImpl;
  36 import com.sun.org.apache.xerces.internal.dom.NotationImpl;
  37 import com.sun.org.apache.xerces.internal.dom.PSVIAttrNSImpl;
  38 import com.sun.org.apache.xerces.internal.dom.PSVIDocumentImpl;
  39 import com.sun.org.apache.xerces.internal.dom.PSVIElementNSImpl;
  40 import com.sun.org.apache.xerces.internal.dom.TextImpl;
  41 import com.sun.org.apache.xerces.internal.impl.Constants;
  42 import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType;
  43 import com.sun.org.apache.xerces.internal.util.DOMErrorHandlerWrapper;
  44 import com.sun.org.apache.xerces.internal.utils.ObjectFactory;
  45 import com.sun.org.apache.xerces.internal.xni.Augmentations;
  46 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  47 import com.sun.org.apache.xerces.internal.xni.QName;
  48 import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
  49 import com.sun.org.apache.xerces.internal.xni.XMLLocator;
  50 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
  51 import com.sun.org.apache.xerces.internal.xni.XMLString;
  52 import com.sun.org.apache.xerces.internal.xni.XNIException;
  53 import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration;
  54 import com.sun.org.apache.xerces.internal.xs.AttributePSVI;
  55 import com.sun.org.apache.xerces.internal.xs.ElementPSVI;
  56 import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
  57 import java.util.Locale;
  58 import java.util.Stack;
  59 import org.w3c.dom.Attr;
  60 import org.w3c.dom.CDATASection;
  61 import org.w3c.dom.Comment;
  62 import org.w3c.dom.DOMError;
  63 import org.w3c.dom.Document;
  64 import org.w3c.dom.DocumentType;
  65 import org.w3c.dom.Element;
  66 import org.w3c.dom.EntityReference;
  67 import org.w3c.dom.NamedNodeMap;
  68 import org.w3c.dom.Node;
  69 import org.w3c.dom.NodeList;
  70 import org.w3c.dom.ProcessingInstruction;
  71 import org.w3c.dom.Text;
  72 import org.w3c.dom.ls.LSParserFilter;
  73 import org.w3c.dom.traversal.NodeFilter;
  74 import org.xml.sax.SAXException;
  75 
  76 /**
  77  * This is the base class of all DOM parsers. It implements the XNI
  78  * callback methods to create the DOM tree. After a successful parse of
  79  * an XML document, the DOM Document object can be queried using the
  80  * <code>getDocument</code> method. The actual pipeline is defined in
  81  * parser configuration.
  82  *
  83  * @author Arnaud Le Hors, IBM
  84  * @author Andy Clark, IBM
  85  * @author Elena Litani, IBM
  86  *
  87  * @LastModified: Nov 2017
  88  */
  89 public class AbstractDOMParser extends AbstractXMLDocumentParser {
  90 
  91     //
  92     // Constants
  93     //
  94 
  95     // feature ids
  96 
  97     /** Feature id: namespace. */
  98     protected static final String NAMESPACES =
  99     Constants.SAX_FEATURE_PREFIX+Constants.NAMESPACES_FEATURE;
 100 
 101     /** Feature id: create entity ref nodes. */
 102     protected static final String CREATE_ENTITY_REF_NODES =
 103     Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_ENTITY_REF_NODES_FEATURE;
 104 
 105     /** Feature id: include comments. */
 106     protected static final String INCLUDE_COMMENTS_FEATURE =
 107     Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_COMMENTS_FEATURE;
 108 
 109     /** Feature id: create cdata nodes. */
 110     protected static final String CREATE_CDATA_NODES_FEATURE =
 111     Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_CDATA_NODES_FEATURE;
 112 
 113     /** Feature id: include ignorable whitespace. */
 114     protected static final String INCLUDE_IGNORABLE_WHITESPACE =
 115     Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_IGNORABLE_WHITESPACE;
 116 
 117     /** Feature id: defer node expansion. */
 118     protected static final String DEFER_NODE_EXPANSION =
 119     Constants.XERCES_FEATURE_PREFIX + Constants.DEFER_NODE_EXPANSION_FEATURE;
 120 
 121 
 122     /** Recognized features. */
 123     private static final String[] RECOGNIZED_FEATURES = {
 124         NAMESPACES,
 125         CREATE_ENTITY_REF_NODES,
 126         INCLUDE_COMMENTS_FEATURE,
 127         CREATE_CDATA_NODES_FEATURE,
 128         INCLUDE_IGNORABLE_WHITESPACE,
 129         DEFER_NODE_EXPANSION
 130     };
 131 
 132     // property ids
 133 
 134     /** Property id: document class name. */
 135     protected static final String DOCUMENT_CLASS_NAME =
 136     Constants.XERCES_PROPERTY_PREFIX + Constants.DOCUMENT_CLASS_NAME_PROPERTY;
 137 
 138     protected static final String  CURRENT_ELEMENT_NODE=
 139     Constants.XERCES_PROPERTY_PREFIX + Constants.CURRENT_ELEMENT_NODE_PROPERTY;
 140 
 141     // protected static final String GRAMMAR_POOL =
 142     // Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
 143 
 144     /** Recognized properties. */
 145     private static final String[] RECOGNIZED_PROPERTIES = {
 146         DOCUMENT_CLASS_NAME,
 147         CURRENT_ELEMENT_NODE,
 148     };
 149 
 150     // other
 151 
 152     /** Default document class name. */
 153     protected static final String DEFAULT_DOCUMENT_CLASS_NAME =
 154     "com.sun.org.apache.xerces.internal.dom.DocumentImpl";
 155 
 156     protected static final String CORE_DOCUMENT_CLASS_NAME =
 157     "com.sun.org.apache.xerces.internal.dom.CoreDocumentImpl";
 158 
 159     protected static final String PSVI_DOCUMENT_CLASS_NAME =
 160     "com.sun.org.apache.xerces.internal.dom.PSVIDocumentImpl";
 161 
 162     /**
 163      * If the user stops the process, this exception will be thrown.
 164      */
 165     static final class Abort extends RuntimeException {
 166         private static final long serialVersionUID = 1687848994976808490L;
 167         static final Abort INSTANCE = new Abort();
 168         private Abort() {}
 169         public Throwable fillInStackTrace() {
 170             return this;
 171         }
 172     }
 173 
 174     // debugging
 175 
 176     private static final boolean DEBUG_EVENTS = false;
 177     private static final boolean DEBUG_BASEURI = false;
 178 
 179     //
 180     // Data
 181     //
 182 
 183     /** DOM L3 error handler */
 184     protected DOMErrorHandlerWrapper fErrorHandler = null;
 185 
 186     /** True if inside DTD. */
 187     protected boolean fInDTD;
 188 
 189     // features
 190 
 191     /** Create entity reference nodes. */
 192     protected boolean fCreateEntityRefNodes;
 193 
 194     /** Include ignorable whitespace. */
 195     protected boolean fIncludeIgnorableWhitespace;
 196 
 197     /** Include Comments. */
 198     protected boolean fIncludeComments;
 199 
 200     /** Create cdata nodes. */
 201     protected boolean fCreateCDATANodes;
 202 
 203     // dom information
 204 
 205     /** The document. */
 206     protected Document fDocument;
 207 
 208     /** The default Xerces document implementation, if used. */
 209     protected CoreDocumentImpl fDocumentImpl;
 210 
 211     /** Whether to store PSVI information in DOM tree. */
 212     protected boolean fStorePSVI;
 213 
 214     /** The document class name to use. */
 215     protected String  fDocumentClassName;
 216 
 217     /** The document type node. */
 218     protected DocumentType fDocumentType;
 219 
 220     /** Current node. */
 221     protected Node fCurrentNode;
 222     protected CDATASection fCurrentCDATASection;
 223     protected EntityImpl fCurrentEntityDecl;
 224     protected int fDeferredEntityDecl;
 225 
 226     /** Character buffer */
 227     protected final StringBuilder fStringBuilder = new StringBuilder (50);
 228 
 229     // internal subset
 230 
 231     /** Internal subset buffer. */
 232     protected StringBuilder fInternalSubset;
 233 
 234     // deferred expansion data
 235 
 236     protected boolean              fDeferNodeExpansion;
 237     protected boolean              fNamespaceAware;
 238     protected DeferredDocumentImpl fDeferredDocumentImpl;
 239     protected int                  fDocumentIndex;
 240     protected int                  fDocumentTypeIndex;
 241     protected int                  fCurrentNodeIndex;
 242     protected int                  fCurrentCDATASectionIndex;
 243 
 244     // state
 245 
 246     /** True if inside DTD external subset. */
 247     protected boolean fInDTDExternalSubset;
 248 
 249     /** Root element node. */
 250     protected Node fRoot;
 251 
 252     /** True if inside CDATA section. */
 253     protected boolean fInCDATASection;
 254 
 255     /** True if saw the first chunk of characters*/
 256     protected boolean fFirstChunk = false;
 257 
 258 
 259     /** LSParserFilter: specifies that element with given QNAME and all its children
 260      * must be rejected */
 261     protected boolean fFilterReject = false;
 262 
 263     // data
 264 
 265     /** Base uri stack*/
 266     protected final Stack<String> fBaseURIStack = new Stack<>();
 267 
 268     /** LSParserFilter: tracks the element depth within a rejected subtree. */
 269     protected int fRejectedElementDepth = 0;
 270 
 271     /** LSParserFilter: store depth of skipped elements */
 272     protected Stack<Boolean> fSkippedElemStack = null;
 273 
 274     /** LSParserFilter: true if inside entity reference */
 275     protected boolean fInEntityRef = false;
 276 
 277     /** Attribute QName. */
 278     private final QName fAttrQName = new QName();
 279 
 280     /** Document locator. */
 281     private XMLLocator fLocator;
 282 
 283     // handlers
 284 
 285     protected LSParserFilter fDOMFilter = null;
 286 
 287     //
 288     // Constructors
 289     //
 290 
 291     /** Default constructor. */
 292     protected AbstractDOMParser (XMLParserConfiguration config) {
 293 
 294         super (config);
 295 
 296 
 297         // add recognized features
 298         fConfiguration.addRecognizedFeatures (RECOGNIZED_FEATURES);
 299 
 300         // set default values
 301         fConfiguration.setFeature (CREATE_ENTITY_REF_NODES, true);
 302         fConfiguration.setFeature (INCLUDE_IGNORABLE_WHITESPACE, true);
 303         fConfiguration.setFeature (DEFER_NODE_EXPANSION, true);
 304         fConfiguration.setFeature (INCLUDE_COMMENTS_FEATURE, true);
 305         fConfiguration.setFeature (CREATE_CDATA_NODES_FEATURE, true);
 306 
 307         // add recognized properties
 308         fConfiguration.addRecognizedProperties (RECOGNIZED_PROPERTIES);
 309 
 310         // set default values
 311         fConfiguration.setProperty (DOCUMENT_CLASS_NAME,
 312         DEFAULT_DOCUMENT_CLASS_NAME);
 313 
 314     } // <init>(XMLParserConfiguration)
 315 
 316     /**
 317      * This method retrieves the name of current document class.
 318      */
 319     protected String getDocumentClassName () {
 320         return fDocumentClassName;
 321     }
 322 
 323     /**
 324      * This method allows the programmer to decide which document
 325      * factory to use when constructing the DOM tree. However, doing
 326      * so will lose the functionality of the default factory. Also,
 327      * a document class other than the default will lose the ability
 328      * to defer node expansion on the DOM tree produced.
 329      *
 330      * @param documentClassName The fully qualified class name of the
 331      *                      document factory to use when constructing
 332      *                      the DOM tree.
 333      *
 334      * @see #getDocumentClassName
 335      * @see #DEFAULT_DOCUMENT_CLASS_NAME
 336      */
 337     protected void setDocumentClassName (String documentClassName) {
 338 
 339         // normalize class name
 340         if (documentClassName == null) {
 341             documentClassName = DEFAULT_DOCUMENT_CLASS_NAME;
 342         }
 343 
 344         if (!documentClassName.equals(DEFAULT_DOCUMENT_CLASS_NAME) &&
 345             !documentClassName.equals(PSVI_DOCUMENT_CLASS_NAME)) {
 346             // verify that this class exists and is of the right type
 347             try {
 348                 Class<?> _class = ObjectFactory.findProviderClass (documentClassName, true);
 349                 //if (!_class.isAssignableFrom(Document.class)) {
 350                 if (!Document.class.isAssignableFrom (_class)) {
 351                     throw new IllegalArgumentException (
 352                         DOMMessageFormatter.formatMessage(
 353                         DOMMessageFormatter.DOM_DOMAIN,
 354                         "InvalidDocumentClassName", new Object [] {documentClassName}));
 355                 }
 356             }
 357             catch (ClassNotFoundException e) {
 358                 throw new IllegalArgumentException (
 359                     DOMMessageFormatter.formatMessage(
 360                     DOMMessageFormatter.DOM_DOMAIN,
 361                     "MissingDocumentClassName", new Object [] {documentClassName}));
 362             }
 363         }
 364 
 365         // set document class name
 366         fDocumentClassName = documentClassName;
 367         if (!documentClassName.equals (DEFAULT_DOCUMENT_CLASS_NAME)) {
 368             fDeferNodeExpansion = false;
 369         }
 370 
 371     } // setDocumentClassName(String)
 372 
 373     //
 374     // Public methods
 375     //
 376 
 377     /** Returns the DOM document object. */
 378     public Document getDocument () {
 379         return fDocument;
 380     } // getDocument():Document
 381 
 382     /**
 383      * Drops all references to the last DOM which was built by this parser.
 384      */
 385     public final void dropDocumentReferences() {
 386         fDocument = null;
 387         fDocumentImpl = null;
 388         fDeferredDocumentImpl = null;
 389         fDocumentType = null;
 390         fCurrentNode = null;
 391         fCurrentCDATASection = null;
 392         fCurrentEntityDecl = null;
 393         fRoot = null;
 394     } // dropDocumentReferences()
 395 
 396     //
 397     // XMLDocumentParser methods
 398     //
 399 
 400     /**
 401      * Resets the parser state.
 402      *
 403      * @throws SAXException Thrown on initialization error.
 404      */
 405     public void reset () throws XNIException {
 406         super.reset ();
 407 
 408 
 409         // get feature state
 410         fCreateEntityRefNodes =
 411         fConfiguration.getFeature (CREATE_ENTITY_REF_NODES);
 412 
 413         fIncludeIgnorableWhitespace =
 414         fConfiguration.getFeature (INCLUDE_IGNORABLE_WHITESPACE);
 415 
 416         fDeferNodeExpansion =
 417         fConfiguration.getFeature (DEFER_NODE_EXPANSION);
 418 
 419         fNamespaceAware = fConfiguration.getFeature (NAMESPACES);
 420 
 421         fIncludeComments = fConfiguration.getFeature (INCLUDE_COMMENTS_FEATURE);
 422 
 423         fCreateCDATANodes = fConfiguration.getFeature (CREATE_CDATA_NODES_FEATURE);
 424 
 425         // get property
 426         setDocumentClassName ((String)
 427         fConfiguration.getProperty (DOCUMENT_CLASS_NAME));
 428 
 429         // reset dom information
 430         fDocument = null;
 431         fDocumentImpl = null;
 432         fStorePSVI = false;
 433         fDocumentType = null;
 434         fDocumentTypeIndex = -1;
 435         fDeferredDocumentImpl = null;
 436         fCurrentNode = null;
 437 
 438         // reset string buffer
 439         fStringBuilder.setLength (0);
 440 
 441         // reset state information
 442         fRoot = null;
 443         fInDTD = false;
 444         fInDTDExternalSubset = false;
 445         fInCDATASection = false;
 446         fFirstChunk = false;
 447         fCurrentCDATASection = null;
 448         fCurrentCDATASectionIndex = -1;
 449 
 450         fBaseURIStack.removeAllElements ();
 451 
 452 
 453     } // reset()
 454 
 455     /**
 456      * Set the locale to use for messages.
 457      *
 458      * @param locale The locale object to use for localization of messages.
 459      *
 460      */
 461     public void setLocale (Locale locale) {
 462         fConfiguration.setLocale (locale);
 463 
 464     } // setLocale(Locale)
 465 
 466     //
 467     // XMLDocumentHandler methods
 468     //
 469 
 470     /**
 471      * This method notifies the start of a general entity.
 472      * <p>
 473      * <strong>Note:</strong> This method is not called for entity references
 474      * appearing as part of attribute values.
 475      *
 476      * @param name     The name of the general entity.
 477      * @param identifier The resource identifier.
 478      * @param encoding The auto-detected IANA encoding name of the entity
 479      *                 stream. This value will be null in those situations
 480      *                 where the entity encoding is not auto-detected (e.g.
 481      *                 internal entities or a document entity that is
 482      *                 parsed from a java.io.Reader).
 483      * @param augs     Additional information that may include infoset augmentations
 484      *
 485      * @exception XNIException Thrown by handler to signal an error.
 486      */
 487     public void startGeneralEntity (String name,
 488     XMLResourceIdentifier identifier,
 489     String encoding, Augmentations augs)
 490     throws XNIException {
 491         if (DEBUG_EVENTS) {
 492             System.out.println ("==>startGeneralEntity ("+name+")");
 493             if (DEBUG_BASEURI) {
 494                 System.out.println ("   expandedSystemId( **baseURI): "+identifier.getExpandedSystemId ());
 495                 System.out.println ("   baseURI:"+ identifier.getBaseSystemId ());
 496             }
 497         }
 498 
 499         // Always create entity reference nodes to be able to recreate
 500         // entity as a part of doctype
 501         if (!fDeferNodeExpansion) {
 502             if (fFilterReject) {
 503                 return;
 504             }
 505             setCharacterData (true);
 506             EntityReference er = fDocument.createEntityReference (name);
 507             if (fDocumentImpl != null) {
 508                 // REVISIT: baseURI/actualEncoding
 509                 //         remove dependency on our implementation when DOM L3 is REC
 510                 //
 511 
 512                 EntityReferenceImpl erImpl =(EntityReferenceImpl)er;
 513 
 514                 // set base uri
 515                 erImpl.setBaseURI (identifier.getExpandedSystemId ());
 516                 if (fDocumentType != null) {
 517                     // set actual encoding
 518                     NamedNodeMap entities = fDocumentType.getEntities ();
 519                     fCurrentEntityDecl = (EntityImpl) entities.getNamedItem (name);
 520                     if (fCurrentEntityDecl != null) {
 521                         fCurrentEntityDecl.setInputEncoding (encoding);
 522                     }
 523 
 524                 }
 525                 // we don't need synchronization now, because entity ref will be
 526                 // expanded anyway. Synch only needed when user creates entityRef node
 527                 erImpl.needsSyncChildren (false);
 528             }
 529             fInEntityRef = true;
 530             fCurrentNode.appendChild (er);
 531             fCurrentNode = er;
 532         }
 533         else {
 534 
 535             int er =
 536             fDeferredDocumentImpl.createDeferredEntityReference (name, identifier.getExpandedSystemId ());
 537             if (fDocumentTypeIndex != -1) {
 538                 // find corresponding Entity decl
 539                 int node = fDeferredDocumentImpl.getLastChild (fDocumentTypeIndex, false);
 540                 while (node != -1) {
 541                     short nodeType = fDeferredDocumentImpl.getNodeType (node, false);
 542                     if (nodeType == Node.ENTITY_NODE) {
 543                         String nodeName =
 544                         fDeferredDocumentImpl.getNodeName (node, false);
 545                         if (nodeName.equals (name)) {
 546                             fDeferredEntityDecl = node;
 547                             fDeferredDocumentImpl.setInputEncoding (node, encoding);
 548                             break;
 549                         }
 550                     }
 551                     node = fDeferredDocumentImpl.getRealPrevSibling (node, false);
 552                 }
 553             }
 554             fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, er);
 555             fCurrentNodeIndex = er;
 556         }
 557 
 558     } // startGeneralEntity(String,XMLResourceIdentifier, Augmentations)
 559 
 560     /**
 561      * Notifies of the presence of a TextDecl line in an entity. If present,
 562      * this method will be called immediately following the startEntity call.
 563      * <p>
 564      * <strong>Note:</strong> This method will never be called for the
 565      * document entity; it is only called for external general entities
 566      * referenced in document content.
 567      * <p>
 568      * <strong>Note:</strong> This method is not called for entity references
 569      * appearing as part of attribute values.
 570      *
 571      * @param version  The XML version, or null if not specified.
 572      * @param encoding The IANA encoding name of the entity.
 573      * @param augs       Additional information that may include infoset augmentations
 574      *
 575      * @throws XNIException Thrown by handler to signal an error.
 576      */
 577     public void textDecl (String version, String encoding, Augmentations augs) throws XNIException {
 578         if (fInDTD){
 579             return;
 580         }
 581         if (!fDeferNodeExpansion) {
 582             if (fCurrentEntityDecl != null && !fFilterReject) {
 583                 fCurrentEntityDecl.setXmlEncoding (encoding);
 584                 if (version != null)
 585                     fCurrentEntityDecl.setXmlVersion (version);
 586             }
 587         }
 588         else {
 589             if (fDeferredEntityDecl !=-1) {
 590                 fDeferredDocumentImpl.setEntityInfo (fDeferredEntityDecl, version, encoding);
 591             }
 592         }
 593     } // textDecl(String,String)
 594 
 595     /**
 596      * A comment.
 597      *
 598      * @param text The text in the comment.
 599      * @param augs       Additional information that may include infoset augmentations
 600      *
 601      * @throws XNIException Thrown by application to signal an error.
 602      */
 603     @SuppressWarnings("fallthrough") // by design at case LSParserFilter.FILTER_SKIP
 604     public void comment (XMLString text, Augmentations augs) throws XNIException {
 605         if (fInDTD) {
 606             if (fInternalSubset != null && !fInDTDExternalSubset) {
 607                 fInternalSubset.append ("<!--");
 608                 if (text.length > 0) {
 609                     fInternalSubset.append (text.ch, text.offset, text.length);
 610                 }
 611                 fInternalSubset.append ("-->");
 612             }
 613             return;
 614         }
 615         if (!fIncludeComments || fFilterReject) {
 616             return;
 617         }
 618         if (!fDeferNodeExpansion) {
 619             Comment comment = fDocument.createComment (text.toString ());
 620 
 621             setCharacterData (false);
 622             fCurrentNode.appendChild (comment);
 623             if (fDOMFilter !=null && !fInEntityRef &&
 624             (fDOMFilter.getWhatToShow () & NodeFilter.SHOW_COMMENT)!= 0) {
 625                 short code = fDOMFilter.acceptNode (comment);
 626                 switch (code) {
 627                     case LSParserFilter.FILTER_INTERRUPT:{
 628                         throw Abort.INSTANCE;
 629                     }
 630                     case LSParserFilter.FILTER_REJECT:{
 631                         // REVISIT: the constant FILTER_REJECT should be changed when new
 632                         // DOM LS specs gets published
 633 
 634                         // fall through to SKIP since comment has no children.
 635                     }
 636                     case LSParserFilter.FILTER_SKIP: {
 637                         // REVISIT: the constant FILTER_SKIP should be changed when new
 638                         // DOM LS specs gets published
 639                         fCurrentNode.removeChild (comment);
 640                         // make sure we don't loose chars if next event is characters()
 641                         fFirstChunk = true;
 642                         return;
 643                     }
 644 
 645                     default: {
 646                         // accept node
 647                     }
 648                 }
 649             }
 650 
 651         }
 652         else {
 653             int comment =
 654             fDeferredDocumentImpl.createDeferredComment (text.toString ());
 655             fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, comment);
 656         }
 657 
 658     } // comment(XMLString)
 659 
 660     /**
 661      * A processing instruction. Processing instructions consist of a
 662      * target name and, optionally, text data. The data is only meaningful
 663      * to the application.
 664      * <p>
 665      * Typically, a processing instruction's data will contain a series
 666      * of pseudo-attributes. These pseudo-attributes follow the form of
 667      * element attributes but are <strong>not</strong> parsed or presented
 668      * to the application as anything other than text. The application is
 669      * responsible for parsing the data.
 670      *
 671      * @param target The target.
 672      * @param data   The data or null if none specified.
 673      * @param augs       Additional information that may include infoset augmentations
 674      *
 675      * @throws XNIException Thrown by handler to signal an error.
 676      */
 677     @SuppressWarnings("fallthrough") // by design at case LSParserFilter.FILTER_REJECT
 678     public void processingInstruction (String target, XMLString data, Augmentations augs)
 679     throws XNIException {
 680 
 681         if (fInDTD) {
 682             if (fInternalSubset != null && !fInDTDExternalSubset) {
 683                 fInternalSubset.append ("<?");
 684                 fInternalSubset.append (target);
 685                 if (data.length > 0) {
 686                     fInternalSubset.append (' ').append (data.ch, data.offset, data.length);
 687                 }
 688                 fInternalSubset.append ("?>");
 689             }
 690             return;
 691         }
 692 
 693         if (DEBUG_EVENTS) {
 694             System.out.println ("==>processingInstruction ("+target+")");
 695         }
 696         if (!fDeferNodeExpansion) {
 697             if (fFilterReject) {
 698                 return;
 699             }
 700             ProcessingInstruction pi =
 701             fDocument.createProcessingInstruction (target, data.toString ());
 702 
 703 
 704             setCharacterData (false);
 705             fCurrentNode.appendChild (pi);
 706             if (fDOMFilter !=null && !fInEntityRef &&
 707             (fDOMFilter.getWhatToShow () & NodeFilter.SHOW_PROCESSING_INSTRUCTION)!= 0) {
 708                 short code = fDOMFilter.acceptNode (pi);
 709                 switch (code) {
 710                     case LSParserFilter.FILTER_INTERRUPT:{
 711                         throw Abort.INSTANCE;
 712                     }
 713                     case LSParserFilter.FILTER_REJECT:{
 714                         // fall through to SKIP since PI has no children.
 715                     }
 716                     case LSParserFilter.FILTER_SKIP: {
 717                         fCurrentNode.removeChild (pi);
 718                         // fFirstChunk must be set to true so that data
 719                         // won't be lost in the case where the child before PI is
 720                         // a text node and the next event is characters.
 721                         fFirstChunk = true;
 722                         return;
 723                     }
 724                     default: {
 725                     }
 726                 }
 727             }
 728         }
 729         else {
 730             int pi = fDeferredDocumentImpl.
 731             createDeferredProcessingInstruction (target, data.toString ());
 732             fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, pi);
 733         }
 734 
 735     } // processingInstruction(String,XMLString)
 736 
 737     /**
 738      * The start of the document.
 739      *
 740      * @param locator The system identifier of the entity if the entity
 741      *                 is external, null otherwise.
 742      * @param encoding The auto-detected IANA encoding name of the entity
 743      *                 stream. This value will be null in those situations
 744      *                 where the entity encoding is not auto-detected (e.g.
 745      *                 internal entities or a document entity that is
 746      *                 parsed from a java.io.Reader).
 747      * @param namespaceContext
 748      *                 The namespace context in effect at the
 749      *                 start of this document.
 750      *                 This object represents the current context.
 751      *                 Implementors of this class are responsible
 752      *                 for copying the namespace bindings from the
 753      *                 the current context (and its parent contexts)
 754      *                 if that information is important.
 755      * @param augs     Additional information that may include infoset augmentations
 756      *
 757      * @throws XNIException Thrown by handler to signal an error.
 758      */
 759     public void startDocument (XMLLocator locator, String encoding,
 760     NamespaceContext namespaceContext, Augmentations augs)
 761     throws XNIException {
 762 
 763         fLocator = locator;
 764         if (!fDeferNodeExpansion) {
 765             if (fDocumentClassName.equals (DEFAULT_DOCUMENT_CLASS_NAME)) {
 766                 fDocument = new DocumentImpl ();
 767                 fDocumentImpl = (CoreDocumentImpl)fDocument;
 768                 // REVISIT: when DOM Level 3 is REC rely on Document.support
 769                 //          instead of specific class
 770                 // set DOM error checking off
 771                 fDocumentImpl.setStrictErrorChecking (false);
 772                 // set actual encoding
 773                 fDocumentImpl.setInputEncoding (encoding);
 774                 // set documentURI
 775                 fDocumentImpl.setDocumentURI (locator.getExpandedSystemId ());
 776             }
 777             else if (fDocumentClassName.equals (PSVI_DOCUMENT_CLASS_NAME)) {
 778                 fDocument = new PSVIDocumentImpl();
 779                 fDocumentImpl = (CoreDocumentImpl)fDocument;
 780                 fStorePSVI = true;
 781                 // REVISIT: when DOM Level 3 is REC rely on Document.support
 782                 //          instead of specific class
 783                 // set DOM error checking off
 784                 fDocumentImpl.setStrictErrorChecking (false);
 785                 // set actual encoding
 786                 fDocumentImpl.setInputEncoding (encoding);
 787                 // set documentURI
 788                 fDocumentImpl.setDocumentURI (locator.getExpandedSystemId ());
 789             }
 790             else {
 791                 // use specified document class
 792                 try {
 793                     Class<?> documentClass = ObjectFactory.findProviderClass (fDocumentClassName, true);
 794                     fDocument = (Document)documentClass.getConstructor().newInstance();
 795 
 796                     // if subclass of our own class that's cool too
 797                     Class<?> defaultDocClass =
 798                     ObjectFactory.findProviderClass (CORE_DOCUMENT_CLASS_NAME, true);
 799                     if (defaultDocClass.isAssignableFrom (documentClass)) {
 800                         fDocumentImpl = (CoreDocumentImpl)fDocument;
 801 
 802                         Class<?> psviDocClass = ObjectFactory.findProviderClass (PSVI_DOCUMENT_CLASS_NAME, true);
 803                         if (psviDocClass.isAssignableFrom (documentClass)) {
 804                             fStorePSVI = true;
 805                         }
 806 
 807                         // REVISIT: when DOM Level 3 is REC rely on
 808                         //          Document.support instead of specific class
 809                         // set DOM error checking off
 810                         fDocumentImpl.setStrictErrorChecking (false);
 811                         // set actual encoding
 812                         fDocumentImpl.setInputEncoding (encoding);
 813                         // set documentURI
 814                         if (locator != null) {
 815                             fDocumentImpl.setDocumentURI (locator.getExpandedSystemId ());
 816                         }
 817                     }
 818                 }
 819                 catch (ClassNotFoundException e) {
 820                     // won't happen we already checked that earlier
 821                 }
 822                 catch (Exception e) {
 823                     throw new RuntimeException (
 824                         DOMMessageFormatter.formatMessage(
 825                         DOMMessageFormatter.DOM_DOMAIN,
 826                         "CannotCreateDocumentClass",
 827                         new Object [] {fDocumentClassName}));
 828                 }
 829             }
 830             fCurrentNode = fDocument;
 831         }
 832         else {
 833             fDeferredDocumentImpl = new DeferredDocumentImpl (fNamespaceAware);
 834             fDocument = fDeferredDocumentImpl;
 835             fDocumentIndex = fDeferredDocumentImpl.createDeferredDocument ();
 836             // REVISIT: strict error checking is not implemented in deferred dom.
 837             //          Document.support instead of specific class
 838 
 839             // set actual encoding
 840             fDeferredDocumentImpl.setInputEncoding (encoding);
 841             // set documentURI
 842             fDeferredDocumentImpl.setDocumentURI (locator.getExpandedSystemId ());
 843             fCurrentNodeIndex = fDocumentIndex;
 844 
 845         }
 846 
 847     } // startDocument(String,String)
 848 
 849     /**
 850      * Notifies of the presence of an XMLDecl line in the document. If
 851      * present, this method will be called immediately following the
 852      * startDocument call.
 853      *
 854      * @param version    The XML version.
 855      * @param encoding   The IANA encoding name of the document, or null if
 856      *                   not specified.
 857      * @param standalone The standalone value, or null if not specified.
 858      * @param augs       Additional information that may include infoset augmentations
 859      *
 860      * @throws XNIException Thrown by handler to signal an error.
 861      */
 862     public void xmlDecl (String version, String encoding, String standalone,
 863     Augmentations augs)
 864     throws XNIException {
 865         if (!fDeferNodeExpansion) {
 866             // REVISIT: when DOM Level 3 is REC rely on Document.support
 867             //          instead of specific class
 868             if (fDocumentImpl != null) {
 869                 if (version != null)
 870                     fDocumentImpl.setXmlVersion (version);
 871                 fDocumentImpl.setXmlEncoding (encoding);
 872                 fDocumentImpl.setXmlStandalone ("yes".equals (standalone));
 873             }
 874         }
 875         else {
 876             if (version != null)
 877                 fDeferredDocumentImpl.setXmlVersion (version);
 878             fDeferredDocumentImpl.setXmlEncoding (encoding);
 879             fDeferredDocumentImpl.setXmlStandalone ("yes".equals (standalone));
 880         }
 881     } // xmlDecl(String,String,String)
 882 
 883     /**
 884      * Notifies of the presence of the DOCTYPE line in the document.
 885      *
 886      * @param rootElement The name of the root element.
 887      * @param publicId    The public identifier if an external DTD or null
 888      *                    if the external DTD is specified using SYSTEM.
 889      * @param systemId    The system identifier if an external DTD, null
 890      *                    otherwise.
 891      * @param augs     Additional information that may include infoset augmentations
 892      *
 893      * @throws XNIException Thrown by handler to signal an error.
 894      */
 895     public void doctypeDecl (String rootElement,
 896     String publicId, String systemId, Augmentations augs)
 897     throws XNIException {
 898 
 899         if (!fDeferNodeExpansion) {
 900             if (fDocumentImpl != null) {
 901                 fDocumentType = fDocumentImpl.createDocumentType (
 902                 rootElement, publicId, systemId);
 903                 fCurrentNode.appendChild (fDocumentType);
 904             }
 905         }
 906         else {
 907             fDocumentTypeIndex = fDeferredDocumentImpl.
 908             createDeferredDocumentType (rootElement, publicId, systemId);
 909             fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, fDocumentTypeIndex);
 910         }
 911 
 912     } // doctypeDecl(String,String,String)
 913 
 914     /**
 915      * The start of an element. If the document specifies the start element
 916      * by using an empty tag, then the startElement method will immediately
 917      * be followed by the endElement method, with no intervening methods.
 918      *
 919      * @param element    The name of the element.
 920      * @param attributes The element attributes.
 921      * @param augs     Additional information that may include infoset augmentations
 922      *
 923      * @throws XNIException Thrown by handler to signal an error.
 924      */
 925     public void startElement (QName element, XMLAttributes attributes, Augmentations augs)
 926     throws XNIException {
 927         if (DEBUG_EVENTS) {
 928             System.out.println ("==>startElement ("+element.rawname+")");
 929         }
 930         if (!fDeferNodeExpansion) {
 931             if (fFilterReject) {
 932                 ++fRejectedElementDepth;
 933                 return;
 934             }
 935             Element el = createElementNode (element);
 936             int attrCount = attributes.getLength ();
 937             boolean seenSchemaDefault = false;
 938             for (int i = 0; i < attrCount; i++) {
 939                 attributes.getName (i, fAttrQName);
 940                 Attr attr = createAttrNode (fAttrQName);
 941 
 942                 String attrValue = attributes.getValue (i);
 943 
 944                 AttributePSVI attrPSVI =(AttributePSVI) attributes.getAugmentations (i).getItem (Constants.ATTRIBUTE_PSVI);
 945                 if (fStorePSVI && attrPSVI != null){
 946                     ((PSVIAttrNSImpl) attr).setPSVI (attrPSVI);
 947                 }
 948 
 949                 attr.setValue (attrValue);
 950                 boolean specified = attributes.isSpecified(i);
 951                 // Take special care of schema defaulted attributes. Calling the
 952                 // non-namespace aware setAttributeNode() method could overwrite
 953                 // another attribute with the same local name.
 954                 if (!specified && (seenSchemaDefault || (fAttrQName.uri != null &&
 955                     fAttrQName.uri != NamespaceContext.XMLNS_URI && fAttrQName.prefix == null))) {
 956                     el.setAttributeNodeNS(attr);
 957                     seenSchemaDefault = true;
 958                 }
 959                 else {
 960                     el.setAttributeNode(attr);
 961                 }
 962                 // NOTE: The specified value MUST be set after you set
 963                 //       the node value because that turns the "specified"
 964                 //       flag to "true" which may overwrite a "false"
 965                 //       value from the attribute list. -Ac
 966                 if (fDocumentImpl != null) {
 967                     AttrImpl attrImpl = (AttrImpl) attr;
 968                     Object type = null;
 969                     boolean id = false;
 970 
 971                     // REVISIT: currently it is possible that someone turns off
 972                     // namespaces and turns on xml schema validation
 973                     // To avoid classcast exception in AttrImpl check for namespaces
 974                     // however the correct solution should probably disallow setting
 975                     // namespaces to false when schema processing is turned on.
 976                     if (attrPSVI != null && fNamespaceAware) {
 977                         // XML Schema
 978                         type = attrPSVI.getMemberTypeDefinition ();
 979                         if (type == null) {
 980                             type = attrPSVI.getTypeDefinition ();
 981                             if (type != null) {
 982                                 id = ((XSSimpleType) type).isIDType ();
 983                                 attrImpl.setType (type);
 984                             }
 985                         }
 986                         else {
 987                             id = ((XSSimpleType) type).isIDType ();
 988                             attrImpl.setType (type);
 989                         }
 990                     }
 991                     else {
 992                         // DTD
 993                         boolean isDeclared = Boolean.TRUE.equals (attributes.getAugmentations (i).getItem (Constants.ATTRIBUTE_DECLARED));
 994                         // For DOM Level 3 TypeInfo, the type name must
 995                         // be null if this attribute has not been declared
 996                         // in the DTD.
 997                         if (isDeclared) {
 998                             type = attributes.getType (i);
 999                             id = "ID".equals (type);
1000                         }
1001                         attrImpl.setType (type);
1002                     }
1003 
1004                     if (id) {
1005                         ((ElementImpl) el).setIdAttributeNode (attr, true);
1006                     }
1007 
1008                     attrImpl.setSpecified (specified);
1009                     // REVISIT: Handle entities in attribute value.
1010                 }
1011             }
1012             setCharacterData (false);
1013 
1014             if (augs != null) {
1015                 ElementPSVI elementPSVI = (ElementPSVI)augs.getItem (Constants.ELEMENT_PSVI);
1016                 if (elementPSVI != null && fNamespaceAware) {
1017                     XSTypeDefinition type = elementPSVI.getMemberTypeDefinition ();
1018                     if (type == null) {
1019                         type = elementPSVI.getTypeDefinition ();
1020                     }
1021                     ((ElementNSImpl)el).setType (type);
1022                 }
1023             }
1024 
1025 
1026             // filter nodes
1027             if (fDOMFilter != null && !fInEntityRef) {
1028                 if (fRoot == null) {
1029                     // fill value of the root element
1030                     fRoot = el;
1031                 } else {
1032                     short code = fDOMFilter.startElement(el);
1033                     switch (code) {
1034                         case LSParserFilter.FILTER_INTERRUPT :
1035                             {
1036                                 throw Abort.INSTANCE;
1037                             }
1038                         case LSParserFilter.FILTER_REJECT :
1039                             {
1040                                 fFilterReject = true;
1041                                 fRejectedElementDepth = 0;
1042                                 return;
1043                             }
1044                         case LSParserFilter.FILTER_SKIP :
1045                             {
1046                                 // make sure that if any char data is available
1047                                 // the fFirstChunk is true, so that if the next event
1048                                 // is characters(), and the last node is text, we will copy
1049                                 // the value already in the text node to fStringBuffer
1050                                 // (not to lose it).
1051                                 fFirstChunk = true;
1052                                 fSkippedElemStack.push(Boolean.TRUE);
1053                                 return;
1054                             }
1055                         default :
1056                             {
1057                                 if (!fSkippedElemStack.isEmpty()) {
1058                                     fSkippedElemStack.push(Boolean.FALSE);
1059                                 }
1060                             }
1061                     }
1062                 }
1063             }
1064             fCurrentNode.appendChild (el);
1065             fCurrentNode = el;
1066         }
1067         else {
1068             int el = fDeferredDocumentImpl.createDeferredElement (fNamespaceAware ?
1069                     element.uri : null, element.rawname);
1070             Object type = null;
1071             int attrCount = attributes.getLength ();
1072             // Need to loop in reverse order so that the attributes
1073             // are processed in document order when the DOM is expanded.
1074             for (int i = attrCount - 1; i >= 0; --i) {
1075 
1076                 // set type information
1077                 AttributePSVI attrPSVI = (AttributePSVI)attributes.getAugmentations (i).getItem (Constants.ATTRIBUTE_PSVI);
1078                 boolean id = false;
1079 
1080                 // REVISIT: currently it is possible that someone turns off
1081                 // namespaces and turns on xml schema validation
1082                 // To avoid classcast exception in AttrImpl check for namespaces
1083                 // however the correct solution should probably disallow setting
1084                 // namespaces to false when schema processing is turned on.
1085                 if (attrPSVI != null && fNamespaceAware) {
1086                     // XML Schema
1087                     type = attrPSVI.getMemberTypeDefinition ();
1088                     if (type == null) {
1089                         type = attrPSVI.getTypeDefinition ();
1090                         if (type != null){
1091                             id = ((XSSimpleType) type).isIDType ();
1092                         }
1093                     }
1094                     else {
1095                         id = ((XSSimpleType) type).isIDType ();
1096                     }
1097                 }
1098                 else {
1099                     // DTD
1100                     boolean isDeclared = Boolean.TRUE.equals (attributes.getAugmentations (i).getItem (Constants.ATTRIBUTE_DECLARED));
1101                     // For DOM Level 3 TypeInfo, the type name must
1102                     // be null if this attribute has not been declared
1103                     // in the DTD.
1104                     if (isDeclared) {
1105                         type = attributes.getType (i);
1106                         id = "ID".equals (type);
1107                     }
1108                 }
1109 
1110                 // create attribute
1111                 fDeferredDocumentImpl.setDeferredAttribute (
1112                 el,
1113                 attributes.getQName (i),
1114                 attributes.getURI (i),
1115                 attributes.getValue (i),
1116                 attributes.isSpecified (i),
1117                 id,
1118                 type);
1119             }
1120 
1121             fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, el);
1122             fCurrentNodeIndex = el;
1123         }
1124     } // startElement(QName,XMLAttributes)
1125 
1126 
1127     /**
1128      * An empty element.
1129      *
1130      * @param element    The name of the element.
1131      * @param attributes The element attributes.
1132      * @param augs   Additional information that may include infoset augmentations
1133      *
1134      * @throws XNIException Thrown by handler to signal an error.
1135      */
1136     public void emptyElement (QName element, XMLAttributes attributes, Augmentations augs)
1137     throws XNIException {
1138 
1139         startElement (element, attributes, augs);
1140         endElement (element, augs);
1141 
1142     } // emptyElement(QName,XMLAttributes)
1143 
1144     /**
1145      * Character content.
1146      *
1147      * @param text The content.
1148      * @param augs     Additional information that may include infoset augmentations
1149      *
1150      * @throws XNIException Thrown by handler to signal an error.
1151      */
1152     public void characters (XMLString text, Augmentations augs) throws XNIException {
1153 
1154         if (DEBUG_EVENTS) {
1155             System.out.println ("==>characters(): "+text.toString ());
1156         }
1157 
1158         if (!fDeferNodeExpansion) {
1159 
1160             if (fFilterReject) {
1161                 return;
1162             }
1163             if (fInCDATASection && fCreateCDATANodes) {
1164                 if (fCurrentCDATASection == null) {
1165                     fCurrentCDATASection =
1166                     fDocument.createCDATASection (text.toString ());
1167                     fCurrentNode.appendChild (fCurrentCDATASection);
1168                     fCurrentNode = fCurrentCDATASection;
1169                 }
1170                 else {
1171                     fCurrentCDATASection.appendData (text.toString ());
1172                 }
1173             }
1174             else if (!fInDTD) {
1175                 // if type is union (XML Schema) it is possible that we receive
1176                 // character call with empty data
1177                 if (text.length == 0) {
1178                     return;
1179                 }
1180 
1181                 Node child = fCurrentNode.getLastChild ();
1182                 if (child != null && child.getNodeType () == Node.TEXT_NODE) {
1183                     // collect all the data into the string buffer.
1184                     if (fFirstChunk) {
1185                         if (fDocumentImpl != null) {
1186                             fStringBuilder.append (((TextImpl)child).removeData ());
1187                         } else {
1188                             fStringBuilder.append (((Text)child).getData ());
1189                             ((Text)child).setNodeValue (null);
1190                         }
1191                         fFirstChunk = false;
1192                     }
1193                     if (text.length > 0) {
1194                         fStringBuilder.append (text.ch, text.offset, text.length);
1195                     }
1196                 }
1197                 else {
1198                     fFirstChunk = true;
1199                     Text textNode = fDocument.createTextNode (text.toString());
1200                     fCurrentNode.appendChild (textNode);
1201                 }
1202 
1203             }
1204         }
1205         else {
1206             // The Text and CDATASection normalization is taken care of within
1207             // the DOM in the deferred case.
1208             if (fInCDATASection && fCreateCDATANodes) {
1209                 if (fCurrentCDATASectionIndex == -1) {
1210                     int cs = fDeferredDocumentImpl.
1211                     createDeferredCDATASection (text.toString ());
1212 
1213                     fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, cs);
1214                     fCurrentCDATASectionIndex = cs;
1215                     fCurrentNodeIndex = cs;
1216                 }
1217                 else {
1218                     int txt = fDeferredDocumentImpl.
1219                     createDeferredTextNode (text.toString (), false);
1220                     fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, txt);
1221                 }
1222             } else if (!fInDTD) {
1223                 // if type is union (XML Schema) it is possible that we receive
1224                 // character call with empty data
1225                 if (text.length == 0) {
1226                     return;
1227                 }
1228 
1229                 String value = text.toString ();
1230                 int txt = fDeferredDocumentImpl.
1231                 createDeferredTextNode (value, false);
1232                 fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, txt);
1233 
1234             }
1235         }
1236     } // characters(XMLString)
1237 
1238     /**
1239      * Ignorable whitespace. For this method to be called, the document
1240      * source must have some way of determining that the text containing
1241      * only whitespace characters should be considered ignorable. For
1242      * example, the validator can determine if a length of whitespace
1243      * characters in the document are ignorable based on the element
1244      * content model.
1245      *
1246      * @param text The ignorable whitespace.
1247      * @param augs     Additional information that may include infoset augmentations
1248      *
1249      * @throws XNIException Thrown by handler to signal an error.
1250      */
1251     public void ignorableWhitespace (XMLString text, Augmentations augs) throws XNIException {
1252 
1253         if (!fIncludeIgnorableWhitespace || fFilterReject) {
1254             return;
1255         }
1256         if (!fDeferNodeExpansion) {
1257             Node child = fCurrentNode.getLastChild ();
1258             if (child != null && child.getNodeType () == Node.TEXT_NODE) {
1259                 Text textNode = (Text)child;
1260                 textNode.appendData (text.toString ());
1261             }
1262             else {
1263                 Text textNode = fDocument.createTextNode (text.toString ());
1264                 if (fDocumentImpl != null) {
1265                     TextImpl textNodeImpl = (TextImpl)textNode;
1266                     textNodeImpl.setIgnorableWhitespace (true);
1267                 }
1268                 fCurrentNode.appendChild (textNode);
1269             }
1270         }
1271         else {
1272             // The Text normalization is taken care of within the DOM in the
1273             // deferred case.
1274             int txt = fDeferredDocumentImpl.
1275             createDeferredTextNode (text.toString (), true);
1276             fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, txt);
1277         }
1278 
1279     } // ignorableWhitespace(XMLString)
1280 
1281     /**
1282      * The end of an element.
1283      *
1284      * @param element The name of the element.
1285      * @param augs     Additional information that may include infoset augmentations
1286      *
1287      * @throws XNIException Thrown by handler to signal an error.
1288      */
1289     public void endElement (QName element, Augmentations augs) throws XNIException {
1290         if (DEBUG_EVENTS) {
1291             System.out.println ("==>endElement ("+element.rawname+")");
1292         }
1293         if (!fDeferNodeExpansion) {
1294 
1295             // REVISIT: Should this happen after we call the filter?
1296             if (augs != null && fDocumentImpl != null && (fNamespaceAware || fStorePSVI)) {
1297                 ElementPSVI elementPSVI = (ElementPSVI) augs.getItem(Constants.ELEMENT_PSVI);
1298                 if (elementPSVI != null) {
1299                     // Updating TypeInfo. If the declared type is a union the
1300                     // [member type definition] will only be available at the
1301                     // end of an element.
1302                     if (fNamespaceAware) {
1303                         XSTypeDefinition type = elementPSVI.getMemberTypeDefinition();
1304                         if (type == null) {
1305                             type = elementPSVI.getTypeDefinition();
1306                         }
1307                         ((ElementNSImpl)fCurrentNode).setType(type);
1308                     }
1309                     if (fStorePSVI) {
1310                         ((PSVIElementNSImpl)fCurrentNode).setPSVI (elementPSVI);
1311                     }
1312                 }
1313             }
1314 
1315             if (fDOMFilter != null) {
1316                 if (fFilterReject) {
1317                     if (fRejectedElementDepth-- == 0) {
1318                         fFilterReject = false;
1319                     }
1320                     return;
1321                 }
1322                 if (!fSkippedElemStack.isEmpty()) {
1323                     if (fSkippedElemStack.pop() == Boolean.TRUE) {
1324                         return;
1325                     }
1326                 }
1327                 setCharacterData (false);
1328                 if ((fCurrentNode != fRoot) && !fInEntityRef && (fDOMFilter.getWhatToShow () & NodeFilter.SHOW_ELEMENT)!=0) {
1329                     short code = fDOMFilter.acceptNode (fCurrentNode);
1330                     switch (code) {
1331                         case LSParserFilter.FILTER_INTERRUPT:{
1332                             throw Abort.INSTANCE;
1333                         }
1334                         case LSParserFilter.FILTER_REJECT:{
1335                             Node parent = fCurrentNode.getParentNode ();
1336                             parent.removeChild (fCurrentNode);
1337                             fCurrentNode = parent;
1338                             return;
1339                         }
1340                         case LSParserFilter.FILTER_SKIP: {
1341                             // make sure that if any char data is available
1342                             // the fFirstChunk is true, so that if the next event
1343                             // is characters(), and the last node is text, we will copy
1344                             // the value already in the text node to fStringBuffer
1345                             // (not to lose it).
1346                             fFirstChunk = true;
1347 
1348                             // replace children
1349                             Node parent = fCurrentNode.getParentNode ();
1350                             NodeList ls = fCurrentNode.getChildNodes ();
1351                             int length = ls.getLength ();
1352 
1353                             for (int i=0;i<length;i++) {
1354                                 parent.appendChild (ls.item (0));
1355                             }
1356                             parent.removeChild (fCurrentNode);
1357                             fCurrentNode = parent;
1358 
1359                             return;
1360                         }
1361 
1362                         default: { }
1363                     }
1364                 }
1365                 fCurrentNode = fCurrentNode.getParentNode ();
1366 
1367             } // end-if DOMFilter
1368             else {
1369                 setCharacterData (false);
1370                 fCurrentNode = fCurrentNode.getParentNode ();
1371             }
1372 
1373         }
1374         else {
1375             if (augs != null) {
1376                 ElementPSVI elementPSVI = (ElementPSVI) augs.getItem(Constants.ELEMENT_PSVI);
1377                 if (elementPSVI != null) {
1378                     // Setting TypeInfo. If the declared type is a union the
1379                     // [member type definition] will only be available at the
1380                     // end of an element.
1381                     XSTypeDefinition type = elementPSVI.getMemberTypeDefinition();
1382                     if (type == null) {
1383                         type = elementPSVI.getTypeDefinition();
1384                     }
1385                     fDeferredDocumentImpl.setTypeInfo(fCurrentNodeIndex, type);
1386                 }
1387             }
1388             fCurrentNodeIndex =
1389                 fDeferredDocumentImpl.getParentNode (fCurrentNodeIndex, false);
1390         }
1391 
1392 
1393     } // endElement(QName)
1394 
1395 
1396     /**
1397      * The start of a CDATA section.
1398      * @param augs     Additional information that may include infoset augmentations
1399      *
1400      * @throws XNIException Thrown by handler to signal an error.
1401      */
1402     public void startCDATA (Augmentations augs) throws XNIException {
1403 
1404         fInCDATASection = true;
1405         if (!fDeferNodeExpansion) {
1406             if (fFilterReject) {
1407                 return;
1408             }
1409             if (fCreateCDATANodes) {
1410                 setCharacterData (false);
1411             }
1412         }
1413     } // startCDATA()
1414 
1415     /**
1416      * The end of a CDATA section.
1417      * @param augs     Additional information that may include infoset augmentations
1418      *
1419      * @throws XNIException Thrown by handler to signal an error.
1420      */
1421     @SuppressWarnings("fallthrough") // by design at case LSParserFilter.FILTER_REJECT
1422     public void endCDATA (Augmentations augs) throws XNIException {
1423 
1424         fInCDATASection = false;
1425         if (!fDeferNodeExpansion) {
1426 
1427             if (fFilterReject) {
1428                 return;
1429             }
1430 
1431             if (fCurrentCDATASection !=null) {
1432 
1433                 if (fDOMFilter !=null && !fInEntityRef &&
1434                 (fDOMFilter.getWhatToShow () & NodeFilter.SHOW_CDATA_SECTION)!= 0) {
1435                     short code = fDOMFilter.acceptNode (fCurrentCDATASection);
1436                     switch (code) {
1437                         case LSParserFilter.FILTER_INTERRUPT:{
1438                             throw Abort.INSTANCE;
1439                         }
1440                         case LSParserFilter.FILTER_REJECT:{
1441                             // fall through to SKIP since CDATA section has no children.
1442                         }
1443                         case LSParserFilter.FILTER_SKIP: {
1444                             Node parent = fCurrentNode.getParentNode ();
1445                             parent.removeChild (fCurrentCDATASection);
1446                             fCurrentNode = parent;
1447                             return;
1448                         }
1449 
1450                         default: {
1451                             // accept node
1452                         }
1453                     }
1454                 }
1455 
1456                 fCurrentNode = fCurrentNode.getParentNode ();
1457                 fCurrentCDATASection = null;
1458             }
1459         }
1460         else {
1461             if (fCurrentCDATASectionIndex !=-1) {
1462                 fCurrentNodeIndex =
1463                 fDeferredDocumentImpl.getParentNode (fCurrentNodeIndex, false);
1464                 fCurrentCDATASectionIndex = -1;
1465             }
1466         }
1467 
1468     } // endCDATA()
1469 
1470     /**
1471      * The end of the document.
1472      * @param augs     Additional information that may include infoset augmentations
1473      *
1474      * @throws XNIException Thrown by handler to signal an error.
1475      */
1476     public void endDocument (Augmentations augs) throws XNIException {
1477 
1478         if (!fDeferNodeExpansion) {
1479             // REVISIT: when DOM Level 3 is REC rely on Document.support
1480             //          instead of specific class
1481             // set the actual encoding and set DOM error checking back on
1482             if (fDocumentImpl != null) {
1483                 if (fLocator != null) {
1484                     if (fLocator.getEncoding() != null)
1485                         fDocumentImpl.setInputEncoding (fLocator.getEncoding());
1486                 }
1487                 fDocumentImpl.setStrictErrorChecking (true);
1488             }
1489             fCurrentNode = null;
1490         }
1491         else {
1492             // set the actual encoding
1493             if (fLocator != null) {
1494                 if (fLocator.getEncoding() != null)
1495                     fDeferredDocumentImpl.setInputEncoding (fLocator.getEncoding());
1496             }
1497             fCurrentNodeIndex = -1;
1498         }
1499 
1500     } // endDocument()
1501 
1502     /**
1503      * This method notifies the end of a general entity.
1504      * <p>
1505      * <strong>Note:</strong> This method is not called for entity references
1506      * appearing as part of attribute values.
1507      *
1508      * @param name   The name of the entity.
1509      * @param augs   Additional information that may include infoset augmentations
1510      *
1511      * @exception XNIException
1512      *                   Thrown by handler to signal an error.
1513      */
1514     public void endGeneralEntity (String name, Augmentations augs) throws XNIException {
1515         if (DEBUG_EVENTS) {
1516             System.out.println ("==>endGeneralEntity: ("+name+")");
1517         }
1518         if (!fDeferNodeExpansion) {
1519 
1520             if (fFilterReject) {
1521                 return;
1522             }
1523             setCharacterData (true);
1524 
1525             if (fDocumentType != null) {
1526                 // get current entity declaration
1527                 NamedNodeMap entities = fDocumentType.getEntities ();
1528                 fCurrentEntityDecl = (EntityImpl) entities.getNamedItem (name);
1529                 if (fCurrentEntityDecl != null) {
1530                     if (fCurrentEntityDecl != null && fCurrentEntityDecl.getFirstChild () == null) {
1531                         fCurrentEntityDecl.setReadOnly (false, true);
1532                         Node child = fCurrentNode.getFirstChild ();
1533                         while (child != null) {
1534                             Node copy = child.cloneNode (true);
1535                             fCurrentEntityDecl.appendChild (copy);
1536                             child = child.getNextSibling ();
1537                         }
1538                         fCurrentEntityDecl.setReadOnly (true, true);
1539 
1540                         //entities.setNamedItem(fCurrentEntityDecl);
1541                     }
1542                     fCurrentEntityDecl = null;
1543                 }
1544 
1545             }
1546             fInEntityRef = false;
1547             boolean removeEntityRef = false;
1548             if (fCreateEntityRefNodes) {
1549                 if (fDocumentImpl != null) {
1550                     // Make entity ref node read only
1551                     ((NodeImpl)fCurrentNode).setReadOnly (true, true);
1552                 }
1553 
1554                 if (fDOMFilter !=null &&
1555                 (fDOMFilter.getWhatToShow () & NodeFilter.SHOW_ENTITY_REFERENCE)!= 0) {
1556                     short code = fDOMFilter.acceptNode (fCurrentNode);
1557                     switch (code) {
1558                         case LSParserFilter.FILTER_INTERRUPT:{
1559                             throw Abort.INSTANCE;
1560                         }
1561                         case LSParserFilter.FILTER_REJECT:{
1562                             Node parent = fCurrentNode.getParentNode ();
1563                             parent.removeChild (fCurrentNode);
1564                             fCurrentNode = parent;
1565                             return;
1566 
1567                         }
1568                         case LSParserFilter.FILTER_SKIP: {
1569                             // make sure we don't loose chars if next event is characters()
1570                             fFirstChunk = true;
1571                             removeEntityRef = true;
1572                             break;
1573                         }
1574 
1575                         default: {
1576                             fCurrentNode = fCurrentNode.getParentNode ();
1577                         }
1578                     }
1579                 } else {
1580                     fCurrentNode = fCurrentNode.getParentNode ();
1581                 }
1582             }
1583 
1584             if (!fCreateEntityRefNodes || removeEntityRef) {
1585                 // move entity reference children to the list of
1586                 // siblings of its parent and remove entity reference
1587                 NodeList children = fCurrentNode.getChildNodes ();
1588                 Node parent = fCurrentNode.getParentNode ();
1589                 int length = children.getLength ();
1590                 if (length > 0) {
1591 
1592                     // get previous sibling of the entity reference
1593                     Node node = fCurrentNode.getPreviousSibling ();
1594                     // normalize text nodes
1595                     Node child = children.item (0);
1596                     if (node != null && node.getNodeType () == Node.TEXT_NODE &&
1597                     child.getNodeType () == Node.TEXT_NODE) {
1598                         ((Text)node).appendData (child.getNodeValue ());
1599                         fCurrentNode.removeChild (child);
1600 
1601                     } else {
1602                         node = parent.insertBefore (child, fCurrentNode);
1603                         handleBaseURI (node);
1604                     }
1605 
1606                     for (int i=1;i <length;i++) {
1607                         node = parent.insertBefore (children.item (0), fCurrentNode);
1608                         handleBaseURI (node);
1609                     }
1610                 } // length > 0
1611                 parent.removeChild (fCurrentNode);
1612                 fCurrentNode = parent;
1613             }
1614         }
1615         else {
1616 
1617             if (fDocumentTypeIndex != -1) {
1618                 // find corresponding Entity decl
1619                 int node = fDeferredDocumentImpl.getLastChild (fDocumentTypeIndex, false);
1620                 while (node != -1) {
1621                     short nodeType = fDeferredDocumentImpl.getNodeType (node, false);
1622                     if (nodeType == Node.ENTITY_NODE) {
1623                         String nodeName =
1624                         fDeferredDocumentImpl.getNodeName (node, false);
1625                         if (nodeName.equals (name)) {
1626                             fDeferredEntityDecl = node;
1627                             break;
1628                         }
1629                     }
1630                     node = fDeferredDocumentImpl.getRealPrevSibling (node, false);
1631                 }
1632             }
1633 
1634             if (fDeferredEntityDecl != -1 &&
1635             fDeferredDocumentImpl.getLastChild (fDeferredEntityDecl, false) == -1) {
1636                 // entity definition exists and it does not have any children
1637                 int prevIndex = -1;
1638                 int childIndex = fDeferredDocumentImpl.getLastChild (fCurrentNodeIndex, false);
1639                 while (childIndex != -1) {
1640                     int cloneIndex = fDeferredDocumentImpl.cloneNode (childIndex, true);
1641                     fDeferredDocumentImpl.insertBefore (fDeferredEntityDecl, cloneIndex, prevIndex);
1642                     prevIndex = cloneIndex;
1643                     childIndex = fDeferredDocumentImpl.getRealPrevSibling (childIndex, false);
1644                 }
1645             }
1646             if (fCreateEntityRefNodes) {
1647                 fCurrentNodeIndex =
1648                 fDeferredDocumentImpl.getParentNode (fCurrentNodeIndex,
1649                 false);
1650             } else { //!fCreateEntityRefNodes
1651                 // move children of entity ref before the entity ref.
1652                 // remove entity ref.
1653 
1654                 // holds a child of entity ref
1655                 int childIndex = fDeferredDocumentImpl.getLastChild (fCurrentNodeIndex, false);
1656                 int parentIndex =
1657                 fDeferredDocumentImpl.getParentNode (fCurrentNodeIndex,
1658                 false);
1659 
1660                 int prevIndex = fCurrentNodeIndex;
1661                 int lastChild = childIndex;
1662                 int sibling = -1;
1663                 while (childIndex != -1) {
1664                     handleBaseURI (childIndex);
1665                     sibling = fDeferredDocumentImpl.getRealPrevSibling (childIndex, false);
1666                     fDeferredDocumentImpl.insertBefore (parentIndex, childIndex, prevIndex);
1667                     prevIndex = childIndex;
1668                     childIndex = sibling;
1669                 }
1670                 if(lastChild != -1)
1671                     fDeferredDocumentImpl.setAsLastChild (parentIndex, lastChild);
1672                 else{
1673                     sibling = fDeferredDocumentImpl.getRealPrevSibling (prevIndex, false);
1674                     fDeferredDocumentImpl.setAsLastChild (parentIndex, sibling);
1675                 }
1676                 fCurrentNodeIndex = parentIndex;
1677             }
1678             fDeferredEntityDecl = -1;
1679         }
1680 
1681 
1682     } // endGeneralEntity(String, Augmentations)
1683 
1684 
1685     /**
1686      * Record baseURI information for the Element (by adding xml:base attribute)
1687      * or for the ProcessingInstruction (by setting a baseURI field)
1688      * Non deferred DOM.
1689      *
1690      * @param node
1691      */
1692     protected final void handleBaseURI (Node node){
1693         if (fDocumentImpl != null) {
1694             // REVISIT: remove dependency on our implementation when
1695             //          DOM L3 becomes REC
1696 
1697             String baseURI = null;
1698             short nodeType = node.getNodeType ();
1699 
1700             if (nodeType == Node.ELEMENT_NODE) {
1701                 // if an element already has xml:base attribute
1702                 // do nothing
1703                 if (fNamespaceAware) {
1704                     if (((Element)node).getAttributeNodeNS ("http://www.w3.org/XML/1998/namespace","base")!=null) {
1705                         return;
1706                     }
1707                 } else if (((Element)node).getAttributeNode ("xml:base") != null) {
1708                     return;
1709                 }
1710                 // retrive the baseURI from the entity reference
1711                 baseURI = ((EntityReferenceImpl)fCurrentNode).getBaseURI ();
1712                 if (baseURI !=null && !baseURI.equals (fDocumentImpl.getDocumentURI ())) {
1713                     if (fNamespaceAware) {
1714                         ((Element)node).setAttributeNS ("http://www.w3.org/XML/1998/namespace", "xml:base", baseURI);
1715                     } else {
1716                         ((Element)node).setAttribute ("xml:base", baseURI);
1717                     }
1718                 }
1719             }
1720             else if (nodeType == Node.PROCESSING_INSTRUCTION_NODE) {
1721 
1722                 baseURI = ((EntityReferenceImpl)fCurrentNode).getBaseURI ();
1723                 if (baseURI !=null && fErrorHandler != null) {
1724                     DOMErrorImpl error = new DOMErrorImpl ();
1725                     error.fType = "pi-base-uri-not-preserved";
1726                     error.fRelatedData = baseURI;
1727                     error.fSeverity = DOMError.SEVERITY_WARNING;
1728                     fErrorHandler.getErrorHandler ().handleError (error);
1729                 }
1730             }
1731         }
1732     }
1733 
1734     /**
1735      *
1736      * Record baseURI information for the Element (by adding xml:base attribute)
1737      * or for the ProcessingInstruction (by setting a baseURI field)
1738      * Deferred DOM.
1739      *
1740      * @param node
1741      */
1742     protected final void handleBaseURI (int node){
1743         short nodeType = fDeferredDocumentImpl.getNodeType (node, false);
1744 
1745         if (nodeType == Node.ELEMENT_NODE) {
1746             String baseURI = fDeferredDocumentImpl.getNodeValueString (fCurrentNodeIndex, false);
1747             if (baseURI == null) {
1748                 baseURI = fDeferredDocumentImpl.getDeferredEntityBaseURI (fDeferredEntityDecl);
1749             }
1750             if (baseURI !=null && !baseURI.equals (fDeferredDocumentImpl.getDocumentURI ())) {
1751                 fDeferredDocumentImpl.setDeferredAttribute (node,
1752                 "xml:base",
1753                 "http://www.w3.org/XML/1998/namespace",
1754                 baseURI,
1755                 true,
1756                 false,
1757                 null);
1758             }
1759         }
1760         else if (nodeType == Node.PROCESSING_INSTRUCTION_NODE) {
1761 
1762 
1763             // retrieve baseURI from the entity reference
1764             String baseURI = fDeferredDocumentImpl.getNodeValueString (fCurrentNodeIndex, false);
1765 
1766             if (baseURI == null) {
1767                 // try baseURI of the entity declaration
1768                 baseURI = fDeferredDocumentImpl.getDeferredEntityBaseURI (fDeferredEntityDecl);
1769             }
1770 
1771             if (baseURI != null && fErrorHandler != null) {
1772                 DOMErrorImpl error = new DOMErrorImpl ();
1773                 error.fType = "pi-base-uri-not-preserved";
1774                 error.fRelatedData = baseURI;
1775                 error.fSeverity = DOMError.SEVERITY_WARNING;
1776                 fErrorHandler.getErrorHandler ().handleError (error);
1777             }
1778         }
1779     }
1780 
1781 
1782     //
1783     // XMLDTDHandler methods
1784     //
1785 
1786     /**
1787      * The start of the DTD.
1788      *
1789      * @param locator  The document locator, or null if the document
1790      *                 location cannot be reported during the parsing of
1791      *                 the document DTD. However, it is <em>strongly</em>
1792      *                 recommended that a locator be supplied that can
1793      *                 at least report the base system identifier of the
1794      *                 DTD.
1795      * @param augs Additional information that may include infoset
1796      *                      augmentations.
1797      *
1798      * @throws XNIException Thrown by handler to signal an error.
1799      */
1800     public void startDTD (XMLLocator locator, Augmentations augs) throws XNIException {
1801         if (DEBUG_EVENTS) {
1802             System.out.println ("==>startDTD");
1803             if (DEBUG_BASEURI) {
1804                 System.out.println ("   expandedSystemId: "+locator.getExpandedSystemId ());
1805                 System.out.println ("   baseURI:"+ locator.getBaseSystemId ());
1806             }
1807         }
1808 
1809         fInDTD = true;
1810         if (locator != null) {
1811             fBaseURIStack.push (locator.getBaseSystemId ());
1812         }
1813         if (fDeferNodeExpansion || fDocumentImpl != null) {
1814             fInternalSubset = new StringBuilder (1024);
1815         }
1816     } // startDTD(XMLLocator)
1817 
1818 
1819     /**
1820      * The end of the DTD.
1821      *
1822      * @param augs Additional information that may include infoset
1823      *                      augmentations.
1824      *
1825      * @throws XNIException Thrown by handler to signal an error.
1826      */
1827     public void endDTD (Augmentations augs) throws XNIException {
1828         if (DEBUG_EVENTS) {
1829             System.out.println ("==>endDTD()");
1830         }
1831         fInDTD = false;
1832         if (!fBaseURIStack.isEmpty ()) {
1833             fBaseURIStack.pop ();
1834         }
1835         String internalSubset = fInternalSubset != null && fInternalSubset.length () > 0
1836         ? fInternalSubset.toString () : null;
1837         if (fDeferNodeExpansion) {
1838             if (internalSubset != null) {
1839                 fDeferredDocumentImpl.setInternalSubset (fDocumentTypeIndex, internalSubset);
1840             }
1841         }
1842         else if (fDocumentImpl != null) {
1843             if (internalSubset != null) {
1844                 ((DocumentTypeImpl)fDocumentType).setInternalSubset (internalSubset);
1845             }
1846         }
1847     } // endDTD()
1848 
1849     /**
1850      * The start of a conditional section.
1851      *
1852      * @param type The type of the conditional section. This value will
1853      *             either be CONDITIONAL_INCLUDE or CONDITIONAL_IGNORE.
1854      * @param augs Additional information that may include infoset
1855      *                      augmentations.
1856      *
1857      * @throws XNIException Thrown by handler to signal an error.
1858      *
1859      * @see #CONDITIONAL_INCLUDE
1860      * @see #CONDITIONAL_IGNORE
1861      */
1862     public void startConditional (short type, Augmentations augs) throws XNIException  {
1863     } // startConditional(short)
1864 
1865     /**
1866      * The end of a conditional section.
1867      *
1868      * @param augs Additional information that may include infoset
1869      *                      augmentations.
1870      *
1871      * @throws XNIException Thrown by handler to signal an error.
1872      */
1873     public void endConditional (Augmentations augs) throws XNIException {
1874     } // endConditional()
1875 
1876 
1877     /**
1878      * The start of the DTD external subset.
1879      *
1880      * @param augs Additional information that may include infoset
1881      *                      augmentations.
1882      *
1883      * @throws XNIException Thrown by handler to signal an error.
1884      */
1885     public void startExternalSubset (XMLResourceIdentifier identifier,
1886     Augmentations augs) throws XNIException {
1887         if (DEBUG_EVENTS) {
1888             System.out.println ("==>startExternalSubset");
1889             if (DEBUG_BASEURI) {
1890                 System.out.println ("   expandedSystemId: "+identifier.getExpandedSystemId ());
1891                 System.out.println ("   baseURI:"+ identifier.getBaseSystemId ());
1892             }
1893         }
1894         fBaseURIStack.push (identifier.getBaseSystemId ());
1895         fInDTDExternalSubset = true;
1896     } // startExternalSubset(Augmentations)
1897 
1898     /**
1899      * The end of the DTD external subset.
1900      *
1901      * @param augs Additional information that may include infoset
1902      *                      augmentations.
1903      *
1904      * @throws XNIException Thrown by handler to signal an error.
1905      */
1906     public void endExternalSubset (Augmentations augs) throws XNIException {
1907         fInDTDExternalSubset = false;
1908         fBaseURIStack.pop ();
1909     } // endExternalSubset(Augmentations)
1910 
1911     /**
1912      * An internal entity declaration.
1913      *
1914      * @param name The name of the entity. Parameter entity names start with
1915      *             '%', whereas the name of a general entity is just the
1916      *             entity name.
1917      * @param text The value of the entity.
1918      * @param nonNormalizedText The non-normalized value of the entity. This
1919      *             value contains the same sequence of characters that was in
1920      *             the internal entity declaration, without any entity
1921      *             references expanded.
1922      * @param augs Additional information that may include infoset
1923      *                      augmentations.
1924      *
1925      * @throws XNIException Thrown by handler to signal an error.
1926      */
1927     public void internalEntityDecl (String name, XMLString text,
1928     XMLString nonNormalizedText,
1929     Augmentations augs) throws XNIException {
1930 
1931         if (DEBUG_EVENTS) {
1932             System.out.println ("==>internalEntityDecl: "+name);
1933             if (DEBUG_BASEURI) {
1934                 System.out.println ("   baseURI:"+ fBaseURIStack.peek ());
1935             }
1936         }
1937         // internal subset string
1938         if (fInternalSubset != null && !fInDTDExternalSubset) {
1939             fInternalSubset.append ("<!ENTITY ");
1940             if (name.startsWith ("%")) {
1941                 fInternalSubset.append ("% ");
1942                 fInternalSubset.append (name.substring (1));
1943             }
1944             else {
1945                 fInternalSubset.append (name);
1946             }
1947             fInternalSubset.append (' ');
1948             String value = nonNormalizedText.toString ();
1949             boolean singleQuote = value.indexOf ('\'') == -1;
1950             fInternalSubset.append (singleQuote ? '\'' : '"');
1951             fInternalSubset.append (value);
1952             fInternalSubset.append (singleQuote ? '\'' : '"');
1953             fInternalSubset.append (">\n");
1954         }
1955 
1956         // NOTE: We only know how to create these nodes for the Xerces
1957         //       DOM implementation because DOM Level 2 does not specify
1958         //       that functionality. -Ac
1959 
1960         // create full node
1961         // don't add parameter entities!
1962         if(name.startsWith ("%"))
1963             return;
1964         if (fDocumentType != null) {
1965             NamedNodeMap entities = fDocumentType.getEntities ();
1966             EntityImpl entity = (EntityImpl)entities.getNamedItem (name);
1967             if (entity == null) {
1968                 entity = (EntityImpl)fDocumentImpl.createEntity (name);
1969                 entity.setBaseURI (fBaseURIStack.peek ());
1970                 entities.setNamedItem (entity);
1971             }
1972         }
1973 
1974         // create deferred node
1975         if (fDocumentTypeIndex != -1) {
1976             boolean found = false;
1977             int node = fDeferredDocumentImpl.getLastChild (fDocumentTypeIndex, false);
1978             while (node != -1) {
1979                 short nodeType = fDeferredDocumentImpl.getNodeType (node, false);
1980                 if (nodeType == Node.ENTITY_NODE) {
1981                     String nodeName = fDeferredDocumentImpl.getNodeName (node, false);
1982                     if (nodeName.equals (name)) {
1983                         found = true;
1984                         break;
1985                     }
1986                 }
1987                 node = fDeferredDocumentImpl.getRealPrevSibling (node, false);
1988             }
1989             if (!found) {
1990                 int entityIndex =
1991                 fDeferredDocumentImpl.createDeferredEntity (name, null, null, null, fBaseURIStack.peek ());
1992                 fDeferredDocumentImpl.appendChild (fDocumentTypeIndex, entityIndex);
1993             }
1994         }
1995 
1996     } // internalEntityDecl(String,XMLString,XMLString)
1997 
1998     /**
1999      * An external entity declaration.
2000      *
2001      * @param name     The name of the entity. Parameter entity names start
2002      *                 with '%', whereas the name of a general entity is just
2003      *                 the entity name.
2004      * @param identifier    An object containing all location information
2005      *                      pertinent to this notation.
2006      * @param augs Additional information that may include infoset
2007      *                      augmentations.
2008      *
2009      * @throws XNIException Thrown by handler to signal an error.
2010      */
2011     public void externalEntityDecl (String name, XMLResourceIdentifier identifier,
2012     Augmentations augs) throws XNIException {
2013 
2014 
2015         if (DEBUG_EVENTS) {
2016             System.out.println ("==>externalEntityDecl: "+name);
2017             if (DEBUG_BASEURI) {
2018                 System.out.println ("   expandedSystemId:"+ identifier.getExpandedSystemId ());
2019                 System.out.println ("   baseURI:"+ identifier.getBaseSystemId ());
2020             }
2021         }
2022         // internal subset string
2023         String publicId = identifier.getPublicId ();
2024         String literalSystemId = identifier.getLiteralSystemId ();
2025         if (fInternalSubset != null && !fInDTDExternalSubset) {
2026             fInternalSubset.append ("<!ENTITY ");
2027             if (name.startsWith ("%")) {
2028                 fInternalSubset.append ("% ");
2029                 fInternalSubset.append (name.substring (1));
2030             }
2031             else {
2032                 fInternalSubset.append (name);
2033             }
2034             fInternalSubset.append (' ');
2035             if (publicId != null) {
2036                 fInternalSubset.append ("PUBLIC '");
2037                 fInternalSubset.append (publicId);
2038                 fInternalSubset.append ("' '");
2039             }
2040             else {
2041                 fInternalSubset.append ("SYSTEM '");
2042             }
2043             fInternalSubset.append (literalSystemId);
2044             fInternalSubset.append ("'>\n");
2045         }
2046 
2047         // NOTE: We only know how to create these nodes for the Xerces
2048         //       DOM implementation because DOM Level 2 does not specify
2049         //       that functionality. -Ac
2050 
2051         // create full node
2052         // don't add parameter entities!
2053         if(name.startsWith ("%"))
2054             return;
2055         if (fDocumentType != null) {
2056             NamedNodeMap entities = fDocumentType.getEntities ();
2057             EntityImpl entity = (EntityImpl)entities.getNamedItem (name);
2058             if (entity == null) {
2059                 entity = (EntityImpl)fDocumentImpl.createEntity (name);
2060                 entity.setPublicId (publicId);
2061                 entity.setSystemId (literalSystemId);
2062                 entity.setBaseURI (identifier.getBaseSystemId ());
2063                 entities.setNamedItem (entity);
2064             }
2065         }
2066 
2067         // create deferred node
2068         if (fDocumentTypeIndex != -1) {
2069             boolean found = false;
2070             int nodeIndex = fDeferredDocumentImpl.getLastChild (fDocumentTypeIndex, false);
2071             while (nodeIndex != -1) {
2072                 short nodeType = fDeferredDocumentImpl.getNodeType (nodeIndex, false);
2073                 if (nodeType == Node.ENTITY_NODE) {
2074                     String nodeName = fDeferredDocumentImpl.getNodeName (nodeIndex, false);
2075                     if (nodeName.equals (name)) {
2076                         found = true;
2077                         break;
2078                     }
2079                 }
2080                 nodeIndex = fDeferredDocumentImpl.getRealPrevSibling (nodeIndex, false);
2081             }
2082             if (!found) {
2083                 int entityIndex = fDeferredDocumentImpl.createDeferredEntity (
2084                 name, publicId, literalSystemId, null, identifier.getBaseSystemId ());
2085                 fDeferredDocumentImpl.appendChild (fDocumentTypeIndex, entityIndex);
2086             }
2087         }
2088 
2089     } // externalEntityDecl(String,XMLResourceIdentifier, Augmentations)
2090 
2091 
2092     /**
2093      * This method notifies of the start of a parameter entity. The parameter
2094      * entity name start with a '%' character.
2095      *
2096      * @param name     The name of the parameter entity.
2097      * @param identifier The resource identifier.
2098      * @param encoding The auto-detected IANA encoding name of the entity
2099      *                 stream. This value will be null in those situations
2100      *                 where the entity encoding is not auto-detected (e.g.
2101      *                 internal parameter entities).
2102      * @param augs Additional information that may include infoset
2103      *                      augmentations.
2104      *
2105      * @throws XNIException Thrown by handler to signal an error.
2106      */
2107     public void startParameterEntity (String name,
2108     XMLResourceIdentifier identifier,
2109     String encoding,
2110     Augmentations augs) throws XNIException {
2111         if (DEBUG_EVENTS) {
2112             System.out.println ("==>startParameterEntity: "+name);
2113             if (DEBUG_BASEURI) {
2114                 System.out.println ("   expandedSystemId: "+identifier.getExpandedSystemId ());
2115                 System.out.println ("   baseURI:"+ identifier.getBaseSystemId ());
2116             }
2117         }
2118         if (augs != null && fInternalSubset != null &&
2119             !fInDTDExternalSubset &&
2120             Boolean.TRUE.equals(augs.getItem(Constants.ENTITY_SKIPPED))) {
2121             fInternalSubset.append(name).append(";\n");
2122         }
2123         fBaseURIStack.push (identifier.getExpandedSystemId ());
2124     }
2125 
2126 
2127     /**
2128      * This method notifies the end of a parameter entity. Parameter entity
2129      * names begin with a '%' character.
2130      *
2131      * @param name The name of the parameter entity.
2132      * @param augs Additional information that may include infoset
2133      *                      augmentations.
2134      *
2135      * @throws XNIException Thrown by handler to signal an error.
2136      */
2137     public void endParameterEntity (String name, Augmentations augs) throws XNIException {
2138 
2139         if (DEBUG_EVENTS) {
2140             System.out.println ("==>endParameterEntity: "+name);
2141         }
2142         fBaseURIStack.pop ();
2143     }
2144 
2145     /**
2146      * An unparsed entity declaration.
2147      *
2148      * @param name     The name of the entity.
2149      * @param identifier    An object containing all location information
2150      *                      pertinent to this entity.
2151      * @param notation The name of the notation.
2152      * @param augs Additional information that may include infoset
2153      *                      augmentations.
2154      *
2155      * @throws XNIException Thrown by handler to signal an error.
2156      */
2157     public void unparsedEntityDecl (String name, XMLResourceIdentifier identifier,
2158     String notation, Augmentations augs)
2159     throws XNIException {
2160 
2161         if (DEBUG_EVENTS) {
2162             System.out.println ("==>unparsedEntityDecl: "+name);
2163             if (DEBUG_BASEURI) {
2164                 System.out.println ("   expandedSystemId:"+ identifier.getExpandedSystemId ());
2165                 System.out.println ("   baseURI:"+ identifier.getBaseSystemId ());
2166             }
2167         }
2168         // internal subset string
2169         String publicId = identifier.getPublicId ();
2170         String literalSystemId = identifier.getLiteralSystemId ();
2171         if (fInternalSubset != null && !fInDTDExternalSubset) {
2172             fInternalSubset.append ("<!ENTITY ");
2173             fInternalSubset.append (name);
2174             fInternalSubset.append (' ');
2175             if (publicId != null) {
2176                 fInternalSubset.append ("PUBLIC '");
2177                 fInternalSubset.append (publicId);
2178                 if (literalSystemId != null) {
2179                     fInternalSubset.append ("' '");
2180                     fInternalSubset.append (literalSystemId);
2181                 }
2182             }
2183             else {
2184                 fInternalSubset.append ("SYSTEM '");
2185                 fInternalSubset.append (literalSystemId);
2186             }
2187             fInternalSubset.append ("' NDATA ");
2188             fInternalSubset.append (notation);
2189             fInternalSubset.append (">\n");
2190         }
2191 
2192         // NOTE: We only know how to create these nodes for the Xerces
2193         //       DOM implementation because DOM Level 2 does not specify
2194         //       that functionality. -Ac
2195 
2196         // create full node
2197         if (fDocumentType != null) {
2198             NamedNodeMap entities = fDocumentType.getEntities ();
2199             EntityImpl entity = (EntityImpl)entities.getNamedItem (name);
2200             if (entity == null) {
2201                 entity = (EntityImpl)fDocumentImpl.createEntity (name);
2202                 entity.setPublicId (publicId);
2203                 entity.setSystemId (literalSystemId);
2204                 entity.setNotationName (notation);
2205                 entity.setBaseURI (identifier.getBaseSystemId ());
2206                 entities.setNamedItem (entity);
2207             }
2208         }
2209 
2210         // create deferred node
2211         if (fDocumentTypeIndex != -1) {
2212             boolean found = false;
2213             int nodeIndex = fDeferredDocumentImpl.getLastChild (fDocumentTypeIndex, false);
2214             while (nodeIndex != -1) {
2215                 short nodeType = fDeferredDocumentImpl.getNodeType (nodeIndex, false);
2216                 if (nodeType == Node.ENTITY_NODE) {
2217                     String nodeName = fDeferredDocumentImpl.getNodeName (nodeIndex, false);
2218                     if (nodeName.equals (name)) {
2219                         found = true;
2220                         break;
2221                     }
2222                 }
2223                 nodeIndex = fDeferredDocumentImpl.getRealPrevSibling (nodeIndex, false);
2224             }
2225             if (!found) {
2226                 int entityIndex = fDeferredDocumentImpl.createDeferredEntity (
2227                 name, publicId, literalSystemId, notation, identifier.getBaseSystemId ());
2228                 fDeferredDocumentImpl.appendChild (fDocumentTypeIndex, entityIndex);
2229             }
2230         }
2231 
2232     } // unparsedEntityDecl(String,XMLResourceIdentifier, String, Augmentations)
2233 
2234     /**
2235      * A notation declaration
2236      *
2237      * @param name     The name of the notation.
2238      * @param identifier    An object containing all location information
2239      *                      pertinent to this notation.
2240      * @param augs Additional information that may include infoset
2241      *                      augmentations.
2242      *
2243      * @throws XNIException Thrown by handler to signal an error.
2244      */
2245     public void notationDecl (String name, XMLResourceIdentifier identifier,
2246     Augmentations augs) throws XNIException {
2247 
2248         // internal subset string
2249         String publicId = identifier.getPublicId ();
2250         String literalSystemId = identifier.getLiteralSystemId ();
2251         if (fInternalSubset != null && !fInDTDExternalSubset) {
2252             fInternalSubset.append ("<!NOTATION ");
2253             fInternalSubset.append (name);
2254             if (publicId != null) {
2255                 fInternalSubset.append (" PUBLIC '");
2256                 fInternalSubset.append (publicId);
2257                 if (literalSystemId != null) {
2258                     fInternalSubset.append ("' '");
2259                     fInternalSubset.append (literalSystemId);
2260                 }
2261             }
2262             else {
2263                 fInternalSubset.append (" SYSTEM '");
2264                 fInternalSubset.append (literalSystemId);
2265             }
2266             fInternalSubset.append ("'>\n");
2267         }
2268 
2269         // NOTE: We only know how to create these nodes for the Xerces
2270         //       DOM implementation because DOM Level 2 does not specify
2271         //       that functionality. -Ac
2272 
2273         // create full node
2274         if (fDocumentImpl !=null && fDocumentType != null) {
2275             NamedNodeMap notations = fDocumentType.getNotations ();
2276             if (notations.getNamedItem (name) == null) {
2277                 NotationImpl notation = (NotationImpl)fDocumentImpl.createNotation (name);
2278                 notation.setPublicId (publicId);
2279                 notation.setSystemId (literalSystemId);
2280                 notation.setBaseURI (identifier.getBaseSystemId ());
2281                 notations.setNamedItem (notation);
2282             }
2283         }
2284 
2285         // create deferred node
2286         if (fDocumentTypeIndex != -1) {
2287             boolean found = false;
2288             int nodeIndex = fDeferredDocumentImpl.getLastChild (fDocumentTypeIndex, false);
2289             while (nodeIndex != -1) {
2290                 short nodeType = fDeferredDocumentImpl.getNodeType (nodeIndex, false);
2291                 if (nodeType == Node.NOTATION_NODE) {
2292                     String nodeName = fDeferredDocumentImpl.getNodeName (nodeIndex, false);
2293                     if (nodeName.equals (name)) {
2294                         found = true;
2295                         break;
2296                     }
2297                 }
2298                 nodeIndex = fDeferredDocumentImpl.getPrevSibling (nodeIndex, false);
2299             }
2300             if (!found) {
2301                 int notationIndex = fDeferredDocumentImpl.createDeferredNotation (
2302                 name, publicId, literalSystemId, identifier.getBaseSystemId ());
2303                 fDeferredDocumentImpl.appendChild (fDocumentTypeIndex, notationIndex);
2304             }
2305         }
2306 
2307     } // notationDecl(String,XMLResourceIdentifier, Augmentations)
2308 
2309     /**
2310      * Characters within an IGNORE conditional section.
2311      *
2312      * @param text The ignored text.
2313      * @param augs Additional information that may include infoset
2314      *                      augmentations.
2315      *
2316      * @throws XNIException Thrown by handler to signal an error.
2317      */
2318     public void ignoredCharacters (XMLString text, Augmentations augs) throws XNIException {
2319     } // ignoredCharacters(XMLString, Augmentations)
2320 
2321 
2322     /**
2323      * An element declaration.
2324      *
2325      * @param name         The name of the element.
2326      * @param contentModel The element content model.
2327      * @param augs Additional information that may include infoset
2328      *                      augmentations.
2329      *
2330      * @throws XNIException Thrown by handler to signal an error.
2331      */
2332     public void elementDecl (String name, String contentModel, Augmentations augs)
2333     throws XNIException {
2334 
2335         // internal subset string
2336         if (fInternalSubset != null && !fInDTDExternalSubset) {
2337             fInternalSubset.append ("<!ELEMENT ");
2338             fInternalSubset.append (name);
2339             fInternalSubset.append (' ');
2340             fInternalSubset.append (contentModel);
2341             fInternalSubset.append (">\n");
2342         }
2343 
2344     } // elementDecl(String,String)
2345 
2346     /**
2347      * An attribute declaration.
2348      *
2349      * @param elementName   The name of the element that this attribute
2350      *                      is associated with.
2351      * @param attributeName The name of the attribute.
2352      * @param type          The attribute type. This value will be one of
2353      *                      the following: "CDATA", "ENTITY", "ENTITIES",
2354      *                      "ENUMERATION", "ID", "IDREF", "IDREFS",
2355      *                      "NMTOKEN", "NMTOKENS", or "NOTATION".
2356      * @param enumeration   If the type has the value "ENUMERATION" or
2357      *                      "NOTATION", this array holds the allowed attribute
2358      *                      values; otherwise, this array is null.
2359      * @param defaultType   The attribute default type. This value will be
2360      *                      one of the following: "#FIXED", "#IMPLIED",
2361      *                      "#REQUIRED", or null.
2362      * @param defaultValue  The attribute default value, or null if no
2363      *                      default value is specified.
2364      * @param nonNormalizedDefaultValue  The attribute default value with no normalization
2365      *                      performed, or null if no default value is specified.
2366      * @param augs Additional information that may include infoset
2367      *                      augmentations.
2368      *
2369      * @throws XNIException Thrown by handler to signal an error.
2370      */
2371     public void attributeDecl (String elementName, String attributeName,
2372     String type, String[] enumeration,
2373     String defaultType, XMLString defaultValue,
2374     XMLString nonNormalizedDefaultValue, Augmentations augs) throws XNIException {
2375 
2376         // internal subset string
2377         if (fInternalSubset != null && !fInDTDExternalSubset) {
2378             fInternalSubset.append ("<!ATTLIST ");
2379             fInternalSubset.append (elementName);
2380             fInternalSubset.append (' ');
2381             fInternalSubset.append (attributeName);
2382             fInternalSubset.append (' ');
2383             if (type.equals ("ENUMERATION")) {
2384                 fInternalSubset.append ('(');
2385                 for (int i = 0; i < enumeration.length; i++) {
2386                     if (i > 0) {
2387                         fInternalSubset.append ('|');
2388                     }
2389                     fInternalSubset.append (enumeration[i]);
2390                 }
2391                 fInternalSubset.append (')');
2392             }
2393             else {
2394                 fInternalSubset.append (type);
2395             }
2396             if (defaultType != null) {
2397                 fInternalSubset.append (' ');
2398                 fInternalSubset.append (defaultType);
2399             }
2400             if (defaultValue != null) {
2401                 fInternalSubset.append (" '");
2402                 for (int i = 0; i < defaultValue.length; i++) {
2403                     char c = defaultValue.ch[defaultValue.offset + i];
2404                     if (c == '\'') {
2405                         fInternalSubset.append ("&apos;");
2406                     }
2407                     else {
2408                         fInternalSubset.append (c);
2409                     }
2410                 }
2411                 fInternalSubset.append ('\'');
2412             }
2413             fInternalSubset.append (">\n");
2414         }
2415         // REVISIT: This code applies to the support of domx/grammar-access
2416         // feature in Xerces 1
2417 
2418         // deferred expansion
2419         if (fDeferredDocumentImpl != null) {
2420 
2421             // get the default value
2422             if (defaultValue != null) {
2423 
2424                 // get element definition
2425                 int elementDefIndex  = fDeferredDocumentImpl.lookupElementDefinition (elementName);
2426 
2427                 // create element definition if not already there
2428                 if (elementDefIndex == -1) {
2429                     elementDefIndex = fDeferredDocumentImpl.createDeferredElementDefinition (elementName);
2430                     fDeferredDocumentImpl.appendChild (fDocumentTypeIndex, elementDefIndex);
2431                 }
2432                 // add default attribute
2433                 boolean nsEnabled = fNamespaceAware;
2434                 String namespaceURI = null;
2435                 if (nsEnabled) {
2436                     // DOM Level 2 wants all namespace declaration attributes
2437                     // to be bound to "http://www.w3.org/2000/xmlns/"
2438                     // So as long as the XML parser doesn't do it, it needs to
2439                     // done here.
2440                     if (attributeName.startsWith("xmlns:") ||
2441                         attributeName.equals("xmlns")) {
2442                         namespaceURI = NamespaceContext.XMLNS_URI;
2443                     }
2444                     else if (attributeName.startsWith("xml:")) {
2445                         namespaceURI = NamespaceContext.XML_URI;
2446                     }
2447                 }
2448                 int attrIndex = fDeferredDocumentImpl.createDeferredAttribute (
2449                         attributeName, namespaceURI, defaultValue.toString(), false);
2450                 if ("ID".equals (type)) {
2451                     fDeferredDocumentImpl.setIdAttribute (attrIndex);
2452                 }
2453                 // REVISIT: set ID type correctly
2454                 fDeferredDocumentImpl.appendChild (elementDefIndex, attrIndex);
2455             }
2456 
2457         } // if deferred
2458 
2459         // full expansion
2460         else if (fDocumentImpl != null) {
2461 
2462             // get the default value
2463             if (defaultValue != null) {
2464 
2465                 // get element definition node
2466                 NamedNodeMap elements = ((DocumentTypeImpl)fDocumentType).getElements ();
2467                 ElementDefinitionImpl elementDef = (ElementDefinitionImpl)elements.getNamedItem (elementName);
2468                 if (elementDef == null) {
2469                     elementDef = fDocumentImpl.createElementDefinition (elementName);
2470                     ((DocumentTypeImpl)fDocumentType).getElements ().setNamedItem (elementDef);
2471                 }
2472 
2473                 // REVISIT: Check for uniqueness of element name? -Ac
2474 
2475                 // create attribute and set properties
2476                 boolean nsEnabled = fNamespaceAware;
2477                 AttrImpl attr;
2478                 if (nsEnabled) {
2479                     String namespaceURI = null;
2480                     // DOM Level 2 wants all namespace declaration attributes
2481                     // to be bound to "http://www.w3.org/2000/xmlns/"
2482                     // So as long as the XML parser doesn't do it, it needs to
2483                     // done here.
2484                     if (attributeName.startsWith("xmlns:") ||
2485                         attributeName.equals("xmlns")) {
2486                         namespaceURI = NamespaceContext.XMLNS_URI;
2487                     }
2488                     else if (attributeName.startsWith("xml:")) {
2489                         namespaceURI = NamespaceContext.XML_URI;
2490                     }
2491                     attr = (AttrImpl)fDocumentImpl.createAttributeNS (namespaceURI,
2492                     attributeName);
2493                 }
2494                 else {
2495                     attr = (AttrImpl)fDocumentImpl.createAttribute (attributeName);
2496                 }
2497                 attr.setValue (defaultValue.toString ());
2498                 attr.setSpecified (false);
2499                 attr.setIdAttribute ("ID".equals (type));
2500 
2501                 // add default attribute to element definition
2502                 if (nsEnabled){
2503                     elementDef.getAttributes ().setNamedItemNS (attr);
2504                 }
2505                 else {
2506                     elementDef.getAttributes ().setNamedItem (attr);
2507                 }
2508             }
2509 
2510         } // if NOT defer-node-expansion
2511 
2512     } // attributeDecl(String,String,String,String[],String,XMLString, XMLString, Augmentations)
2513 
2514 
2515     /**
2516      * The start of an attribute list.
2517      *
2518      * @param elementName The name of the element that this attribute
2519      *                    list is associated with.
2520      * @param augs Additional information that may include infoset
2521      *                      augmentations.
2522      *
2523      * @throws XNIException Thrown by handler to signal an error.
2524      */
2525     public void startAttlist (String elementName, Augmentations augs) throws XNIException {
2526     } // startAttlist(String)
2527 
2528 
2529     /**
2530      * The end of an attribute list.
2531      *
2532      * @param augs Additional information that may include infoset
2533      *                      augmentations.
2534      *
2535      * @throws XNIException Thrown by handler to signal an error.
2536      */
2537     public void endAttlist (Augmentations augs) throws XNIException {
2538     } // endAttlist()
2539 
2540 
2541     // method to create an element node.
2542     // subclasses can override this method to create element nodes in other ways.
2543     protected Element createElementNode (QName element) {
2544         Element el = null;
2545 
2546         if (fNamespaceAware) {
2547             // if we are using xerces DOM implementation, call our
2548             // own constructor to reuse the strings we have here.
2549             if (fDocumentImpl != null) {
2550                 el = fDocumentImpl.createElementNS (element.uri, element.rawname,
2551                 element.localpart);
2552             }
2553             else {
2554                 el = fDocument.createElementNS (element.uri, element.rawname);
2555             }
2556         }
2557         else {
2558             el = fDocument.createElement (element.rawname);
2559         }
2560 
2561         return el;
2562     }
2563 
2564     // method to create an attribute node.
2565     // subclasses can override this method to create attribute nodes in other ways.
2566     protected Attr createAttrNode (QName attrQName) {
2567         Attr attr = null;
2568 
2569         if (fNamespaceAware) {
2570             if (fDocumentImpl != null) {
2571                 // if we are using xerces DOM implementation, call our
2572                 // own constructor to reuse the strings we have here.
2573                 attr = fDocumentImpl.createAttributeNS (attrQName.uri,
2574                 attrQName.rawname,
2575                 attrQName.localpart);
2576             }
2577             else {
2578                 attr = fDocument.createAttributeNS (attrQName.uri,
2579                 attrQName.rawname);
2580             }
2581         }
2582         else {
2583             attr = fDocument.createAttribute (attrQName.rawname);
2584         }
2585 
2586         return attr;
2587     }
2588 
2589     /*
2590      * When the first characters() call is received, the data is stored in
2591      * a new Text node. If right after the first characters() we receive another chunk of data,
2592      * the data from the Text node, following the new characters are appended
2593      * to the fStringBuffer and the text node data is set to empty.
2594      *
2595      * This function is called when the state is changed and the
2596      * data must be appended to the current node.
2597      *
2598      * Note: if DOMFilter is set, you must make sure that if Node is skipped,
2599      * or removed fFistChunk must be set to true, otherwise some data can be lost.
2600      *
2601      */
2602     @SuppressWarnings("fallthrough") // by design at case LSParserFilter.FILTER_REJECT
2603     protected void  setCharacterData (boolean sawChars){
2604 
2605         // handle character data
2606         fFirstChunk = sawChars;
2607 
2608 
2609         // if we have data in the buffer we must have created
2610         // a text node already.
2611 
2612         Node child = fCurrentNode.getLastChild ();
2613         if (child != null) {
2614             if (fStringBuilder.length () > 0) {
2615                 // REVISIT: should this check be performed?
2616                 if (child.getNodeType () == Node.TEXT_NODE) {
2617                     if (fDocumentImpl != null) {
2618                         ((TextImpl)child).replaceData (fStringBuilder.toString ());
2619                     }
2620                     else {
2621                         ((Text)child).setData (fStringBuilder.toString ());
2622                     }
2623                 }
2624                 // reset string buffer
2625                 fStringBuilder.setLength (0);
2626             }
2627 
2628             if (fDOMFilter !=null && !fInEntityRef) {
2629                 if ( (child.getNodeType () == Node.TEXT_NODE ) &&
2630                 ((fDOMFilter.getWhatToShow () & NodeFilter.SHOW_TEXT)!= 0) ) {
2631                     short code = fDOMFilter.acceptNode (child);
2632                     switch (code) {
2633                         case LSParserFilter.FILTER_INTERRUPT:{
2634                             throw Abort.INSTANCE;
2635                         }
2636                         case LSParserFilter.FILTER_REJECT:{
2637                             // fall through to SKIP since Comment has no children.
2638                         }
2639                         case LSParserFilter.FILTER_SKIP: {
2640                             fCurrentNode.removeChild (child);
2641                             return;
2642                         }
2643                         default: {
2644                             // accept node -- do nothing
2645                         }
2646                     }
2647                 }
2648             }   // end-if fDOMFilter !=null
2649 
2650         } // end-if child !=null
2651     }
2652 
2653 
2654     /**
2655      * @see org.w3c.dom.ls.LSParser#abort()
2656      */
2657     public void abort () {
2658         throw Abort.INSTANCE;
2659     }
2660 
2661 
2662 } // class AbstractDOMParser