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