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