Package org.apache.xerces.parsers

Source Code of org.apache.xerces.parsers.AbstractDOMParser

/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2001, 2002 The Apache Software Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution,
*    if any, must include the following acknowledgment:
*       "This product includes software developed by the
*        Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowledgment may appear in the software itself,
*    if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xerces" and "Apache Software Foundation" must
*    not be used to endorse or promote products derived from this
*    software without prior written permission. For written
*    permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
*    nor may "Apache" appear in their name, without prior written
*    permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, International
* Business Machines, Inc., http://www.apache.org.  For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/

package org.apache.xerces.parsers;

import java.util.Locale;
import java.util.Stack;

import org.apache.xerces.dom.AttrImpl;
import org.apache.xerces.dom.CoreDocumentImpl;
import org.apache.xerces.dom.DOMErrorImpl;
import org.apache.xerces.dom.DeferredDocumentImpl;
import org.apache.xerces.dom.DocumentImpl;
import org.apache.xerces.dom.DocumentTypeImpl;
import org.apache.xerces.dom.ElementDefinitionImpl;
import org.apache.xerces.dom.ElementImpl;
import org.apache.xerces.dom.ElementNSImpl;
import org.apache.xerces.dom.EntityImpl;
import org.apache.xerces.dom.EntityReferenceImpl;
import org.apache.xerces.dom.NodeImpl;
import org.apache.xerces.dom.NotationImpl;
import org.apache.xerces.dom.PSVIAttrNSImpl;
import org.apache.xerces.dom.PSVIElementNSImpl;
import org.apache.xerces.dom.ProcessingInstructionImpl;
import org.apache.xerces.dom.TextImpl;
import org.apache.xerces.impl.Constants;
import org.apache.xerces.impl.dv.XSSimpleType;
import org.apache.xerces.impl.xs.psvi.XSTypeDefinition;
import org.apache.xerces.util.DOMErrorHandlerWrapper;
import org.apache.xerces.util.ObjectFactory;
import org.apache.xerces.xni.Augmentations;
import org.apache.xerces.xni.NamespaceContext;
import org.apache.xerces.xni.QName;
import org.apache.xerces.xni.XMLAttributes;
import org.apache.xerces.xni.XMLLocator;
import org.apache.xerces.xni.XMLResourceIdentifier;
import org.apache.xerces.xni.XMLString;
import org.apache.xerces.xni.XNIException;
import org.apache.xerces.xni.parser.XMLParserConfiguration;
import org.apache.xerces.xni.psvi.AttributePSVI;
import org.apache.xerces.xni.psvi.ElementPSVI;
import org.w3c.dom.Attr;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.EntityReference;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ProcessingInstruction;
import org.w3c.dom.Text;
import org.w3c.dom.ls.DOMBuilderFilter;
import org.w3c.dom.traversal.NodeFilter;

/**
* This is the base class of all DOM parsers. It implements the XNI
* callback methods to create the DOM tree. After a successful parse of
* an XML document, the DOM Document object can be queried using the
* <code>getDocument</code> method. The actual pipeline is defined in
* parser configuration.
*
* @author Arnaud Le Hors, IBM
* @author Andy Clark, IBM
* @author Elena Litani, IBM
*
* @version $Id: AbstractDOMParser.java,v 1.84 2003/03/24 14:28:44 elena Exp $
*/
public class AbstractDOMParser extends AbstractXMLDocumentParser {

    //
    // Constants
    //
                        
    // feature ids

    /** Feature id: namespace. */
    protected static final String NAMESPACES =
        Constants.SAX_FEATURE_PREFIX+Constants.NAMESPACES_FEATURE;

    /** Feature id: create entity ref nodes. */
    protected static final String CREATE_ENTITY_REF_NODES =
        Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_ENTITY_REF_NODES_FEATURE;

    /** Feature id: include comments. */
    protected static final String INCLUDE_COMMENTS_FEATURE =
        Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_COMMENTS_FEATURE;

    /** Feature id: create cdata nodes. */
    protected static final String CREATE_CDATA_NODES_FEATURE =
        Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_CDATA_NODES_FEATURE;

    /** Feature id: include ignorable whitespace. */
    protected static final String INCLUDE_IGNORABLE_WHITESPACE =
        Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_IGNORABLE_WHITESPACE;

    /** Feature id: defer node expansion. */
    protected static final String DEFER_NODE_EXPANSION =
        Constants.XERCES_FEATURE_PREFIX + Constants.DEFER_NODE_EXPANSION_FEATURE;


    /** Recognized features. */
    private static final String[] RECOGNIZED_FEATURES = {
        NAMESPACES,
        CREATE_ENTITY_REF_NODES,
        INCLUDE_COMMENTS_FEATURE,
        CREATE_CDATA_NODES_FEATURE,
        INCLUDE_IGNORABLE_WHITESPACE,
        DEFER_NODE_EXPANSION
    };

    // property ids

    /** Property id: document class name. */
    protected static final String DOCUMENT_CLASS_NAME =
        Constants.XERCES_PROPERTY_PREFIX + Constants.DOCUMENT_CLASS_NAME_PROPERTY;

    protected static final String  CURRENT_ELEMENT_NODE= 
        Constants.XERCES_PROPERTY_PREFIX + Constants.CURRENT_ELEMENT_NODE_PROPERTY;

    // protected static final String GRAMMAR_POOL =
    // Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;

    /** Recognized properties. */
    private static final String[] RECOGNIZED_PROPERTIES = {
        DOCUMENT_CLASS_NAME,
        CURRENT_ELEMENT_NODE,
    };

    // other

    /** Default document class name. */
    protected static final String DEFAULT_DOCUMENT_CLASS_NAME =
        "org.apache.xerces.dom.DocumentImpl";

    protected static final String CORE_DOCUMENT_CLASS_NAME =
        "org.apache.xerces.dom.CoreDocumentImpl";

    protected static final String PSVI_DOCUMENT_CLASS_NAME =
        "org.apache.xerces.dom.PSVIDocumentImpl";
   
    // debugging

    private static final boolean DEBUG_EVENTS = false;
    private static final boolean DEBUG_BASEURI = false;

    //
    // Data
    //
   
    /** DOM L3 error handler */
    protected DOMErrorHandlerWrapper fErrorHandler = null;

    /** True if inside DTD. */
    protected boolean fInDTD;

    // features

    /** Create entity reference nodes. */
    protected boolean fCreateEntityRefNodes;

    /** Include ignorable whitespace. */
    protected boolean fIncludeIgnorableWhitespace;

    /** Include Comments. */
    protected boolean fIncludeComments;
                         
    /** Create cdata nodes. */
    protected boolean fCreateCDATANodes;

    // dom information

    /** The document. */
    protected Document fDocument;

    /** The default Xerces document implementation, if used. */
    protected CoreDocumentImpl fDocumentImpl;
   
    /** Whether to store PSVI information in DOM tree. */
    protected boolean fStorePSVI;

    /** The document class name to use. */
    protected String  fDocumentClassName;

    /** The document type node. */
    protected DocumentType fDocumentType;

    /** Current node. */
    protected Node fCurrentNode;
    protected CDATASection fCurrentCDATASection;
    protected EntityImpl fCurrentEntityDecl;
    protected int fDeferredEntityDecl;

    /** Character buffer */
    protected final StringBuffer fStringBuffer = new StringBuffer(50);

    // internal subset

    /** Internal subset buffer. */
    protected StringBuffer fInternalSubset;

    // deferred expansion data

    protected boolean              fDeferNodeExpansion;
    protected boolean              fNamespaceAware;
    protected DeferredDocumentImpl fDeferredDocumentImpl;
    protected int                  fDocumentIndex;
    protected int                  fDocumentTypeIndex;
    protected int                  fCurrentNodeIndex;
    protected int                  fCurrentCDATASectionIndex;

    // state

    /** True if inside DTD external subset. */
    protected boolean fInDTDExternalSubset;

    /** True if inside document. */
    protected boolean fInDocument;

    /** True if inside CDATA section. */
    protected boolean fInCDATASection;

    /** True if saw the first chunk of characters*/
    protected boolean fFirstChunk = false;


    /** DOMBuilderFilter: specifies that element with given QNAME and all its children
        must be rejected */
    protected boolean fFilterReject = false;

    // data

    /** Base uri stack*/
    protected Stack fBaseURIStack = new Stack();


    /** DOMBuilderFilter: the QNAME of rejected element*/   
    protected final QName fRejectedElement = new QName();

    /** DOMBuilderFilter: store qnames of skipped elements*/
    protected Stack fSkippedElemStack = null;
   
    /** Attribute QName. */
    private QName fAttrQName = new QName();

    // handlers

    protected DOMBuilderFilter fDOMFilter = null;

    //
    // Constructors
    //

    /** Default constructor. */
    protected AbstractDOMParser(XMLParserConfiguration config) {
       
        super(config);


        // add recognized features
        fConfiguration.addRecognizedFeatures(RECOGNIZED_FEATURES);

        // set default values
        fConfiguration.setFeature(CREATE_ENTITY_REF_NODES, true);
        fConfiguration.setFeature(INCLUDE_IGNORABLE_WHITESPACE, true);
        fConfiguration.setFeature(DEFER_NODE_EXPANSION, true);
        fConfiguration.setFeature(INCLUDE_COMMENTS_FEATURE, true);
        fConfiguration.setFeature(CREATE_CDATA_NODES_FEATURE, true);

        // add recognized properties
        fConfiguration.addRecognizedProperties(RECOGNIZED_PROPERTIES);

        // set default values
        fConfiguration.setProperty(DOCUMENT_CLASS_NAME,
                                   DEFAULT_DOCUMENT_CLASS_NAME);

    } // <init>(XMLParserConfiguration)

    /**
     * This method retreives the name of current document class.
     */
    protected String getDocumentClassName() {
        return fDocumentClassName;
    }

    /**
     * This method allows the programmer to decide which document
     * factory to use when constructing the DOM tree. However, doing
     * so will lose the functionality of the default factory. Also,
     * a document class other than the default will lose the ability
     * to defer node expansion on the DOM tree produced.
     *
     * @param documentClassName The fully qualified class name of the
     *                      document factory to use when constructing
     *                      the DOM tree.
     *
     * @see #getDocumentClassName
     * @see #DEFAULT_DOCUMENT_CLASS_NAME
     */
    protected void setDocumentClassName(String documentClassName) {

        // normalize class name
        if (documentClassName == null) {
            documentClassName = DEFAULT_DOCUMENT_CLASS_NAME;
        }

        // verify that this class exists and is of the right type
        try {
            Class _class = ObjectFactory.findProviderClass(documentClassName,
                    ObjectFactory.findClassLoader(), true);
            //if (!_class.isAssignableFrom(Document.class)) {
            if (!Document.class.isAssignableFrom(_class)) {
                // REVISIT: message
                throw new IllegalArgumentException("PAR002 Class, \"" +
                                                   documentClassName +
                                 "\", is not of type org.w3c.dom.Document.\n" +
                                                   documentClassName);
            }
        }
        catch (ClassNotFoundException e) {
            // REVISIT: message
            throw new IllegalArgumentException("PAR003 Class, \"" +
                                               documentClassName +
                                               "\", not found.\n" +
                                               documentClassName);
        }

        // set document class name
        fDocumentClassName = documentClassName;
        if (!documentClassName.equals(DEFAULT_DOCUMENT_CLASS_NAME)) {
            fDeferNodeExpansion = false;
        }

    } // setDocumentClassName(String)

    //
    // Public methods
    //

    /** Returns the DOM document object. */
    public Document getDocument() {
        return fDocument;
    } // getDocument():Document

    //
    // XMLDocumentParser methods
    //

    /**
     * Resets the parser state.
     *
     * @throws SAXException Thrown on initialization error.
     */
    public void reset() throws XNIException {
        super.reset();
       
        // get feature state
        fCreateEntityRefNodes =
            fConfiguration.getFeature(CREATE_ENTITY_REF_NODES);

        fIncludeIgnorableWhitespace =
            fConfiguration.getFeature(INCLUDE_IGNORABLE_WHITESPACE);

        fDeferNodeExpansion = 
            fConfiguration.getFeature(DEFER_NODE_EXPANSION);

        fNamespaceAware = fConfiguration.getFeature(NAMESPACES);

        fIncludeComments = fConfiguration.getFeature(INCLUDE_COMMENTS_FEATURE);

        fCreateCDATANodes = fConfiguration.getFeature(CREATE_CDATA_NODES_FEATURE);

        // get property
        setDocumentClassName((String)
                             fConfiguration.getProperty(DOCUMENT_CLASS_NAME));

        // reset dom information
        fDocument = null;
        fDocumentImpl = null;
        fStorePSVI = false;
        fDocumentType = null;
        fDocumentTypeIndex = -1;
        fDeferredDocumentImpl = null;
        fCurrentNode = null;

        // reset string buffer
        fStringBuffer.setLength(0);

        // reset state information
        fInDocument = false;
        fInDTD = false;
        fInDTDExternalSubset = false;
        fInCDATASection = false;
        fFirstChunk = false;
        fCurrentCDATASection = null;
        fCurrentCDATASectionIndex = -1;

        fBaseURIStack.removeAllElements();


    } // reset()

    /**
     * Set the locale to use for messages.
     *
     * @param locale The locale object to use for localization of messages.
     *
     */
    public void setLocale(Locale locale) {
        fConfiguration.setLocale(locale);

    } // setLocale(Locale)

    //
    // XMLDocumentHandler methods
    //

    /**
     * This method notifies the start of a general entity.
     * <p>
     * <strong>Note:</strong> This method is not called for entity references
     * appearing as part of attribute values.
     *
     * @param name     The name of the general entity.
     * @param identifier The resource identifier.
     * @param encoding The auto-detected IANA encoding name of the entity
     *                 stream. This value will be null in those situations
     *                 where the entity encoding is not auto-detected (e.g.
     *                 internal entities or a document entity that is
     *                 parsed from a java.io.Reader).
     * @param augs     Additional information that may include infoset augmentations
     *                
     * @exception XNIException Thrown by handler to signal an error.
     */
    public void startGeneralEntity(String name,
                                   XMLResourceIdentifier identifier,
                                   String encoding, Augmentations augs)
        throws XNIException {
        if (DEBUG_EVENTS) {       
            System.out.println("==>startGeneralEntity ("+name+")");
            if (DEBUG_BASEURI) {           
                System.out.println("   expandedSystemId( **baseURI): "+identifier.getExpandedSystemId());
                System.out.println("   baseURI:"+ identifier.getBaseSystemId());
            }
        }
       
        // Always create entity reference nodes to be able to recreate
        // entity as a part of doctype
         if (!fDeferNodeExpansion) {
             if (fFilterReject) {
                 return;
             }
            setCharacterData(true);
            EntityReference er = fDocument.createEntityReference(name);           
            if (fDocumentImpl != null) {           
                // REVISIT: baseURI/actualEncoding
                //         remove dependency on our implementation when DOM L3 is REC
                //

                EntityReferenceImpl erImpl =(EntityReferenceImpl)er;

                // set base uri
                erImpl.setBaseURI(identifier.getExpandedSystemId());

                if (fDocumentType != null) {
                    // set actual encoding
                    NamedNodeMap entities = fDocumentType.getEntities();
                    fCurrentEntityDecl = (EntityImpl) entities.getNamedItem(name);
                    if (fCurrentEntityDecl != null) {
                        fCurrentEntityDecl.setActualEncoding(encoding);
                    }

                }
                // we don't need synchronization now, because entity ref will be
                // expanded anyway. Synch only needed when user creates entityRef node
                erImpl.needsSyncChildren(false);
            }

            fCurrentNode.appendChild(er);
            fCurrentNode = er;
         }
         else {

            int er =
               fDeferredDocumentImpl.createDeferredEntityReference(name, identifier.getExpandedSystemId());
            if (fDocumentTypeIndex != -1) {
                // find corresponding Entity decl
                int node = fDeferredDocumentImpl.getLastChild(fDocumentTypeIndex, false);
                while (node != -1) {
                    short nodeType = fDeferredDocumentImpl.getNodeType(node, false);
                    if (nodeType == Node.ENTITY_NODE) {
                        String nodeName =
                            fDeferredDocumentImpl.getNodeName(node, false);
                        if (nodeName.equals(name)) {
                            fDeferredEntityDecl = node;
                            fDeferredDocumentImpl.setActualEncoding(node, encoding);
                            break;
                        }
                    }
                    node = fDeferredDocumentImpl.getRealPrevSibling(node, false);
                }
            }
            fDeferredDocumentImpl.appendChild(fCurrentNodeIndex, er);
            fCurrentNodeIndex = er;
         }

    } // startGeneralEntity(String,XMLResourceIdentifier, Augmentations)

    /**
     * Notifies of the presence of a TextDecl line in an entity. If present,
     * this method will be called immediately following the startEntity call.
     * <p>
     * <strong>Note:</strong> This method will never be called for the
     * document entity; it is only called for external general entities
     * referenced in document content.
     * <p>
     * <strong>Note:</strong> This method is not called for entity references
     * appearing as part of attribute values.
     *
     * @param version  The XML version, or null if not specified.
     * @param encoding The IANA encoding name of the entity.
     * @param augs       Additional information that may include infoset augmentations
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void textDecl(String version, String encoding, Augmentations augs) throws XNIException {
        if (fInDTD){
            return;
        }
        if (!fDeferNodeExpansion) {
            if (fCurrentEntityDecl != null && !fFilterReject) {
                fCurrentEntityDecl.setEncoding(encoding);
                fCurrentEntityDecl.setVersion(version);
            }
        }
        else {
            if (fDeferredEntityDecl !=-1) {
               fDeferredDocumentImpl.setEntityInfo(fDeferredEntityDecl, version, encoding);
            }
        }
    } // textDecl(String,String)

    /**
     * A comment.
     *
     * @param text The text in the comment.
     * @param augs       Additional information that may include infoset augmentations
     *
     * @throws XNIException Thrown by application to signal an error.
     */
    public void comment(XMLString text, Augmentations augs) throws XNIException {
        if (fInDTD) {       
            if (fInternalSubset != null && !fInDTDExternalSubset) {
                fInternalSubset.append("<!-- ");
                fInternalSubset.append(text.toString());
                fInternalSubset.append(" -->");
            }
            return;
        }
        if (!fIncludeComments || fFilterReject) {
              return;
        }
        if (!fDeferNodeExpansion) {
            Comment comment = fDocument.createComment(text.toString());

            setCharacterData(false);
            fCurrentNode.appendChild(comment);
            if (fDOMFilter !=null &&
                (fDOMFilter.getWhatToShow() & NodeFilter.SHOW_COMMENT)!= 0) {
                short code = fDOMFilter.acceptNode(comment);
                switch (code) {
                    case DOMBuilderFilter.FILTER_INTERRUPT:{
                        throw new RuntimeException("The normal processing of the document was interrupted.");
                    }  
                    case DOMBuilderFilter.FILTER_REJECT:{
                        // REVISIT: the constant FILTER_REJECT should be changed when new
                        // DOM LS specs gets published

                        // fall through to SKIP since comment has no children.
                    }
                    case DOMBuilderFilter.FILTER_SKIP: {
                        // REVISIT: the constant FILTER_SKIP should be changed when new
                        // DOM LS specs gets published
                        fCurrentNode.removeChild(comment);
                        // make sure we don't loose chars if next event is characters()
                        fFirstChunk = true;
                        return;
                    }

                    default: {
                        // accept node
                    }
                }
            }

        }
        else {
            int comment =
                fDeferredDocumentImpl.createDeferredComment(text.toString());
            fDeferredDocumentImpl.appendChild(fCurrentNodeIndex, comment);
        }

    } // comment(XMLString)

    /**
     * A processing instruction. Processing instructions consist of a
     * target name and, optionally, text data. The data is only meaningful
     * to the application.
     * <p>
     * Typically, a processing instruction's data will contain a series
     * of pseudo-attributes. These pseudo-attributes follow the form of
     * element attributes but are <strong>not</strong> parsed or presented
     * to the application as anything other than text. The application is
     * responsible for parsing the data.
     *
     * @param target The target.
     * @param data   The data or null if none specified.
     * @param augs       Additional information that may include infoset augmentations
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void processingInstruction(String target, XMLString data, Augmentations augs)
        throws XNIException {

        if (fInDTD) {       
            if (fInternalSubset != null && !fInDTDExternalSubset) {
                fInternalSubset.append("<?");
                fInternalSubset.append(target.toString());
                fInternalSubset.append(' ');
                fInternalSubset.append(data.toString());
                fInternalSubset.append("?>");

            }
            return;
        }

        if (DEBUG_EVENTS) {       
            System.out.println("==>processingInstruction ("+target+")");
        }
        if (!fDeferNodeExpansion) {           
            if (fFilterReject) {
                return;
            }
            ProcessingInstruction pi =
                fDocument.createProcessingInstruction(target, data.toString());


            setCharacterData(false);
            fCurrentNode.appendChild(pi);
            if (fDOMFilter !=null &&
                (fDOMFilter.getWhatToShow() & NodeFilter.SHOW_PROCESSING_INSTRUCTION)!= 0) {
                short code = fDOMFilter.acceptNode(pi);
                switch (code) {
                    case DOMBuilderFilter.FILTER_INTERRUPT:{
                        throw new RuntimeException("The normal processing of the document was interrupted.");
                    }  
                    case DOMBuilderFilter.FILTER_REJECT:{
                        // fall through to SKIP since PI has no children.
                    }
                    case DOMBuilderFilter.FILTER_SKIP: {
                        fCurrentNode.removeChild(pi);
                        // fFirstChunk must be set to true so that data
                        // won't be lost in the case where the child before PI is
                        // a text node and the next event is characters.
                        fFirstChunk = true;
                        return;
                    }
                    default: {
                    }
                }
            }
        }
        else {
            int pi = fDeferredDocumentImpl.
                createDeferredProcessingInstruction(target, data.toString());
            fDeferredDocumentImpl.appendChild(fCurrentNodeIndex, pi);
        }

    } // processingInstruction(String,XMLString)

    /**
     * The start of the document.
     *
     * @param locator The system identifier of the entity if the entity
     *                 is external, null otherwise.
     * @param encoding The auto-detected IANA encoding name of the entity
     *                 stream. This value will be null in those situations
     *                 where the entity encoding is not auto-detected (e.g.
     *                 internal entities or a document entity that is
     *                 parsed from a java.io.Reader).
     * @param namespaceContext
     *                 The namespace context in effect at the
     *                 start of this document.
     *                 This object represents the current context.
     *                 Implementors of this class are responsible
     *                 for copying the namespace bindings from the
     *                 the current context (and its parent contexts)
     *                 if that information is important.
     * @param augs     Additional information that may include infoset augmentations
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void startDocument(XMLLocator locator, String encoding,
                              NamespaceContext namespaceContext, Augmentations augs)
        throws XNIException {

        fInDocument = true;
        if (!fDeferNodeExpansion) {
            if (fDocumentClassName.equals(DEFAULT_DOCUMENT_CLASS_NAME)) {
                fDocument = new DocumentImpl();
                fDocumentImpl = (CoreDocumentImpl)fDocument;
                // REVISIT: when DOM Level 3 is REC rely on Document.support
                //          instead of specific class
                // set DOM error checking off
                fDocumentImpl.setStrictErrorChecking(false);
                // set actual encoding
                fDocumentImpl.setActualEncoding(encoding);
                // set documentURI
                fDocumentImpl.setDocumentURI(locator.getExpandedSystemId());
            }
            else {
                // use specified document class
                try {
                    Class documentClass = ObjectFactory.findProviderClass(fDocumentClassName,
                        ObjectFactory.findClassLoader(), true);
                    fDocument = (Document)documentClass.newInstance();

                    // if subclass of our own class that's cool too
                    Class defaultDocClass =
                        ObjectFactory.findProviderClass(CORE_DOCUMENT_CLASS_NAME,
                        ObjectFactory.findClassLoader(), true);
                    if (defaultDocClass.isAssignableFrom(documentClass)) {
                        fDocumentImpl = (CoreDocumentImpl)fDocument;

                        Class psviDocClass = ObjectFactory.findProviderClass(PSVI_DOCUMENT_CLASS_NAME,
                            ObjectFactory.findClassLoader(), true);
                        if (psviDocClass.isAssignableFrom(documentClass)) {
                            fStorePSVI = true;
                        }
                       
                        // REVISIT: when DOM Level 3 is REC rely on
                        //          Document.support instead of specific class
                        // set DOM error checking off
                        fDocumentImpl.setStrictErrorChecking(false);
                        // set actual encoding
                        fDocumentImpl.setActualEncoding(encoding);
                        // set documentURI
                        if (locator != null) {
                            fDocumentImpl.setDocumentURI(locator.getExpandedSystemId());
                        }
                    }
                }
                catch (ClassNotFoundException e) {
                    // won't happen we already checked that earlier
                }
                catch (Exception e) {
                    // REVISIT: Localize this message.
                    throw new RuntimeException(
                                 "Failed to create document object of class: "
                                 + fDocumentClassName);
                }
            }
            fCurrentNode = fDocument;
        }
        else {
            fDeferredDocumentImpl = new DeferredDocumentImpl(fNamespaceAware);
            fDocument = fDeferredDocumentImpl;
            fDocumentIndex = fDeferredDocumentImpl.createDeferredDocument();
            // REVISIT: strict error checking is not implemented in deferred dom.
            //          Document.support instead of specific class

            // set actual encoding
            fDeferredDocumentImpl.setActualEncoding(encoding);
            // set documentURI
            fDeferredDocumentImpl.setDocumentURI(locator.getExpandedSystemId());
            fCurrentNodeIndex = fDocumentIndex;

        }

    } // startDocument(String,String)

    /**
     * Notifies of the presence of an XMLDecl line in the document. If
     * present, this method will be called immediately following the
     * startDocument call.
     *
     * @param version    The XML version.
     * @param encoding   The IANA encoding name of the document, or null if
     *                   not specified.
     * @param standalone The standalone value, or null if not specified.
     * @param augs       Additional information that may include infoset augmentations
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void xmlDecl(String version, String encoding, String standalone,
                        Augmentations augs)
        throws XNIException {
        if (!fDeferNodeExpansion) {
            // REVISIT: when DOM Level 3 is REC rely on Document.support
            //          instead of specific class
            if (fDocumentImpl != null) {
                fDocumentImpl.setVersion(version);
                fDocumentImpl.setEncoding(encoding);
                fDocumentImpl.setStandalone("true".equals(standalone));
            }
        }
        else {
            fDeferredDocumentImpl.setVersion(version);
            fDeferredDocumentImpl.setEncoding(encoding);
            fDeferredDocumentImpl.setStandalone("true".equals(standalone));
        }
    } // xmlDecl(String,String,String)

    /**
     * Notifies of the presence of the DOCTYPE line in the document.
     *
     * @param rootElement The name of the root element.
     * @param publicId    The public identifier if an external DTD or null
     *                    if the external DTD is specified using SYSTEM.
     * @param systemId    The system identifier if an external DTD, null
     *                    otherwise.
     * @param augs     Additional information that may include infoset augmentations
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void doctypeDecl(String rootElement,
                            String publicId, String systemId, Augmentations augs)
        throws XNIException {

        if (!fDeferNodeExpansion) {
            if (fDocumentImpl != null) {
                fDocumentType = fDocumentImpl.createDocumentType(
                                    rootElement, publicId, systemId);
                fCurrentNode.appendChild(fDocumentType);
            }
        }
        else {
            fDocumentTypeIndex = fDeferredDocumentImpl.
                createDeferredDocumentType(rootElement, publicId, systemId);
            fDeferredDocumentImpl.appendChild(fCurrentNodeIndex, fDocumentTypeIndex);
        }

    } // doctypeDecl(String,String,String)

    /**
     * The start of an element. If the document specifies the start element
     * by using an empty tag, then the startElement method will immediately
     * be followed by the endElement method, with no intervening methods.
     *
     * @param element    The name of the element.
     * @param attributes The element attributes.
     * @param augs     Additional information that may include infoset augmentations
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void startElement(QName element, XMLAttributes attributes, Augmentations augs)
        throws XNIException {
        if (DEBUG_EVENTS) {
            System.out.println("==>startElement ("+element.rawname+")");
        }
        if (!fDeferNodeExpansion) {
            if (fFilterReject) {
                return;
            }
            Element el = createElementNode(element);
            int attrCount = attributes.getLength();
            for (int i = 0; i < attrCount; i++) {
                attributes.getName(i, fAttrQName);
                Attr attr = createAttrNode(fAttrQName);

                String attrValue = attributes.getValue(i);

                AttributePSVI attrPSVI =(AttributePSVI) attributes.getAugmentations(i).getItem(Constants.ATTRIBUTE_PSVI);
          if (fStorePSVI && attrPSVI != null){
          ((PSVIAttrNSImpl) attr).setPSVI(attrPSVI);
                }
           
               
                attr.setValue(attrValue);
                el.setAttributeNode(attr);
                // NOTE: The specified value MUST be set after you set
                //       the node value because that turns the "specified"
                //       flag to "true" which may overwrite a "false"
                //       value from the attribute list. -Ac
        if (fDocumentImpl != null) {
          AttrImpl attrImpl = (AttrImpl) attr;
          Object type = null;
          boolean id = false;

          // REVISIT: currently it is possible that someone turns off
          // namespaces and turns on xml schema validation
          // To avoid classcast exception in AttrImpl check for namespaces
          // however the correct solution should probably disallow setting
          // namespaces to false when schema processing is turned on.
          if (attrPSVI != null && fNamespaceAware) {
            // XML Schema
            type = attrPSVI.getMemberTypeDefinition();
            if (type == null) {
              type = attrPSVI.getTypeDefinition();
              if (type != null) {
                id = ((XSSimpleType) type).isIDType();
                attrImpl.setType(type);
              }
            }
            else {
              id = ((XSSimpleType) type).isIDType();
              attrImpl.setType(type);
            }
          }
          else {
            // DTD
                        type = attributes.getType(i);
            attrImpl.setType(type);
            id = (type.equals("ID")) ? true : false;
          }
               
          if (id) {
            ((ElementImpl) el).setIdAttributeNode(attr, true);
          }

          attrImpl.setSpecified(attributes.isSpecified(i));
          // REVISIT: Handle entities in attribute value.
                }
            }
            setCharacterData(false);
           
            if (augs != null) {
                ElementPSVI elementPSVI = (ElementPSVI)augs.getItem(Constants.ELEMENT_PSVI);
                if (elementPSVI != null && fNamespaceAware) {
                    XSTypeDefinition type = elementPSVI.getMemberTypeDefinition();
                    if (type == null) {
                        type = elementPSVI.getTypeDefinition();
                    }
                    ((ElementNSImpl)el).setType(type);
                }
            }

           
            // filter nodes
            if (fDOMFilter != null) {
                short code = fDOMFilter.startElement(el);
                switch (code) {
                    case DOMBuilderFilter.FILTER_INTERRUPT:{
                        throw new RuntimeException("The normal processing of the document was interrupted.");
                    }  
                    case DOMBuilderFilter.FILTER_REJECT:{
                        fFilterReject = true;
                        fRejectedElement.setValues(element);
                        return;
                    }
                    case DOMBuilderFilter.FILTER_SKIP: {
                        fSkippedElemStack.push(element);
                        return;
                    }
                    default: {
                    }
                }
            }

            fCurrentNode.appendChild(el);
            fCurrentNode = el;
        }
        else {
           Object type = null;
           if (augs != null) {
                ElementPSVI elementPSVI = (ElementPSVI)augs.getItem(Constants.ELEMENT_PSVI);
                if (elementPSVI != null) {
                    type = elementPSVI.getMemberTypeDefinition();
                    if (type == null) {
                        type = elementPSVI.getTypeDefinition();
                    }
                }
            }

            int el =
                fDeferredDocumentImpl.createDeferredElement(fNamespaceAware ?
                                                            element.uri : null,
                                                            element.rawname,
                                                            type);
            int attrCount = attributes.getLength();
            for (int i = 0; i < attrCount; i++) {
                // set type information
                AttributePSVI attrPSVI = (AttributePSVI)attributes.getAugmentations(i).getItem(Constants.ATTRIBUTE_PSVI);
                boolean id = false;

                // REVISIT: currently it is possible that someone turns off
                // namespaces and turns on xml schema validation
                // To avoid classcast exception in AttrImpl check for namespaces
                // however the correct solution should probably disallow setting
                // namespaces to false when schema processing is turned on.
        if (attrPSVI != null && fNamespaceAware) {
          // XML Schema
          type = attrPSVI.getMemberTypeDefinition();
          if (type == null) {
            type = attrPSVI.getTypeDefinition();
                        if (type != null){
              id = ((XSSimpleType) type).isIDType();
                        }
          }
          else {
            id = ((XSSimpleType) type).isIDType();
          }
        }
        else {
          // DTD
          type = attributes.getType(i);
          id = (type.equals("ID")) ? true : false;
        }
               
                // create attribute
               fDeferredDocumentImpl.setDeferredAttribute(
                        el,
                        attributes.getQName(i),
                        attributes.getURI(i),
                        attributes.getValue(i),
                        attributes.isSpecified(i),
                        id,
                        type);
            }
           
            fDeferredDocumentImpl.appendChild(fCurrentNodeIndex, el);
            fCurrentNodeIndex = el;
        }
    } // startElement(QName,XMLAttributes)


    /**
     * An empty element.
     *
     * @param element    The name of the element.
     * @param attributes The element attributes.
     * @param augs   Additional information that may include infoset augmentations
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs)
        throws XNIException {

        startElement(element, attributes, augs);
        endElement(element, augs);

    } // emptyElement(QName,XMLAttributes)

    /**
     * Character content.
     *
     * @param text The content.
     * @param augs     Additional information that may include infoset augmentations
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void characters(XMLString text, Augmentations augs) throws XNIException {
       
        if (DEBUG_EVENTS) {
            System.out.println("==>characters(): "+text.toString());
        }

        if (!fDeferNodeExpansion) {

            if (fFilterReject) {
                return;
            }
            if (fInCDATASection && fCreateCDATANodes) {
                if (fCurrentCDATASection == null) {
                    fCurrentCDATASection =
                        fDocument.createCDATASection(text.toString());
                    fCurrentNode.appendChild(fCurrentCDATASection);
                    fCurrentNode = fCurrentCDATASection;
                }
                else {
                    fCurrentCDATASection.appendData(text.toString());
                }
            }
            else if (!fInDTD) {
                // if type is union (XML Schema) it is possible that we receive
                // character call with empty data
                if (text.length == 0) {
                    return;
                }

                String value = text.toString();
                Node child = fCurrentNode.getLastChild();
                if (child != null && child.getNodeType() == Node.TEXT_NODE) {
                    // collect all the data into the string buffer.
                    if (fFirstChunk) {
                        if (fDocumentImpl != null) {
                            fStringBuffer.append(((TextImpl)child).removeData());
                        } else {
                            fStringBuffer.append(((Text)child).getData());
                            ((Text)child).setNodeValue(null);
                        }
                        fFirstChunk = false;
                    }
                    fStringBuffer.append(value);
                }
                else {
                   fFirstChunk = true;
                   Text textNode = fDocument.createTextNode(value);
                   fCurrentNode.appendChild(textNode);
                }
              
            }
        }
        else {
            // The Text and CDATASection normalization is taken care of within
            // the DOM in the deferred case.
            if (fInCDATASection && fCreateCDATANodes) {
                if (fCurrentCDATASectionIndex == -1) {
                    int cs = fDeferredDocumentImpl.
                        createDeferredCDATASection(text.toString());

                    fDeferredDocumentImpl.appendChild(fCurrentNodeIndex, cs);
                    fCurrentCDATASectionIndex = cs;
                    fCurrentNodeIndex = cs;
                }
                else {
                    int txt = fDeferredDocumentImpl.
                        createDeferredTextNode(text.toString(), false);
                    fDeferredDocumentImpl.appendChild(fCurrentNodeIndex, txt);
                }
            } else if (!fInDTD) {
                // if type is union (XML Schema) it is possible that we receive
                // character call with empty data
                if (text.length == 0) {
                    return;
                }

                String value = text.toString();
                int txt = fDeferredDocumentImpl.
                    createDeferredTextNode(value, false);
                fDeferredDocumentImpl.appendChild(fCurrentNodeIndex, txt);

            }
        }
    } // characters(XMLString)

    /**
     * Ignorable whitespace. For this method to be called, the document
     * source must have some way of determining that the text containing
     * only whitespace characters should be considered ignorable. For
     * example, the validator can determine if a length of whitespace
     * characters in the document are ignorable based on the element
     * content model.
     *
     * @param text The ignorable whitespace.
     * @param augs     Additional information that may include infoset augmentations
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException {

        if (!fIncludeIgnorableWhitespace || fFilterReject) {
            return;
        }
        if (!fDeferNodeExpansion) {
            Node child = fCurrentNode.getLastChild();
            if (child != null && child.getNodeType() == Node.TEXT_NODE) {
                Text textNode = (Text)child;
                textNode.appendData(text.toString());
            }
            else {
                Text textNode = fDocument.createTextNode(text.toString());
                if (fDocumentImpl != null) {
                    TextImpl textNodeImpl = (TextImpl)textNode;
                    textNodeImpl.setIgnorableWhitespace(true);
                }
                fCurrentNode.appendChild(textNode);
            }
        }
        else {
            // The Text normalization is taken care of within the DOM in the
            // deferred case.
            int txt = fDeferredDocumentImpl.
                createDeferredTextNode(text.toString(), true);
            fDeferredDocumentImpl.appendChild(fCurrentNodeIndex, txt);
        }

    } // ignorableWhitespace(XMLString)

    /**
     * The end of an element.
     *
     * @param element The name of the element.
     * @param augs     Additional information that may include infoset augmentations
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void endElement(QName element, Augmentations augs) throws XNIException {
        if (DEBUG_EVENTS) {
            System.out.println("==>endElement ("+element.rawname+")");
        }
        if (!fDeferNodeExpansion) {
           
            // REVISIT: Should this happen after we call the filter?
            if (fStorePSVI && augs != null) {
                ElementPSVI elementPSVI = (ElementPSVI)augs.getItem(Constants.ELEMENT_PSVI);
                if (elementPSVI != null) {
                    ((PSVIElementNSImpl)fCurrentNode).setPSVI(elementPSVI);
                }
            }
           
            if (fDOMFilter != null) {           
                if (fFilterReject) {
                    if (element.equals(fRejectedElement)) {
                     fFilterReject = false;
                    }
                    return;
                }
                if (!fSkippedElemStack.isEmpty()) {
                    if (fSkippedElemStack.peek().equals(element)) {
                        fSkippedElemStack.pop();
                        return;
                    }
                }
                setCharacterData(false);
                if ((fDOMFilter.getWhatToShow() & NodeFilter.SHOW_ELEMENT)!=0) {
                    short code = fDOMFilter.acceptNode(fCurrentNode);
                    switch (code) {
                        case DOMBuilderFilter.FILTER_INTERRUPT:{
                            throw new RuntimeException("The normal processing of the document was interrupted.");
                        }  
                        case DOMBuilderFilter.FILTER_REJECT:{
                            Node parent = fCurrentNode.getParentNode();                   
                            parent.removeChild(fCurrentNode);
                            fCurrentNode = parent;
                            return;
                        }
                        case DOMBuilderFilter.FILTER_SKIP: {
                            // make sure that if any char data is available
                            // the fFirstChunk is true, so that if the next event
                            // is characters(), and the last node is text, we will copy
                            // the value already in the text node to fStringBuffer
                            // (not to loose it).
                            fFirstChunk = true;

                            // replace children
                            Node parent = fCurrentNode.getParentNode();
                            NodeList ls = fCurrentNode.getChildNodes();
                            int length = ls.getLength();

                            for (int i=0;i<length;i++) {
                                parent.appendChild(ls.item(0));
                            }                              
                            parent.removeChild(fCurrentNode);
                            fCurrentNode = parent;
                           
                            return;
                        }

                        default: { }
                    }
                }
                fCurrentNode = fCurrentNode.getParentNode();
           
            } // end-if DOMFilter
            else {
                setCharacterData(false);
                fCurrentNode = fCurrentNode.getParentNode();
            }
           
        }
        else {
            fCurrentNodeIndex =
                fDeferredDocumentImpl.getParentNode(fCurrentNodeIndex, false);
        }

       
    } // endElement(QName)


    /**
     * The start of a CDATA section.
     * @param augs     Additional information that may include infoset augmentations
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void startCDATA(Augmentations augs) throws XNIException {

        fInCDATASection = true;
        if (!fDeferNodeExpansion) {
            if (fFilterReject) {
                return;
            }
            setCharacterData(false);
        }
    } // startCDATA()

    /**
     * The end of a CDATA section.
     * @param augs     Additional information that may include infoset augmentations
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void endCDATA(Augmentations augs) throws XNIException {

        fInCDATASection = false;
        if (!fDeferNodeExpansion) {

            if (fFilterReject) {
                return;
            }

            if (fCurrentCDATASection !=null) {

                if (fDOMFilter !=null &&
                    (fDOMFilter.getWhatToShow() & NodeFilter.SHOW_CDATA_SECTION)!= 0) {
                    short code = fDOMFilter.acceptNode(fCurrentCDATASection);
                    switch (code) {
                        case DOMBuilderFilter.FILTER_INTERRUPT:{
                            throw new RuntimeException("The normal processing of the document was interrupted.");
                             }  
                        case DOMBuilderFilter.FILTER_REJECT:{
                            // fall through to SKIP since CDATA section has no children.
                        }
                        case DOMBuilderFilter.FILTER_SKIP: {
                            Node parent = fCurrentNode.getParentNode();                   
                            parent.removeChild(fCurrentCDATASection);
                            fCurrentNode = parent;
                            return;
                        }

                        default: {
                            // accept node
                        }
                    }
                }

                fCurrentNode = fCurrentNode.getParentNode();
                fCurrentCDATASection = null;
            }
        }
        else {
            if (fCurrentCDATASectionIndex !=-1) {           
                fCurrentNodeIndex =
                fDeferredDocumentImpl.getParentNode(fCurrentNodeIndex, false);
                fCurrentCDATASectionIndex = -1;
            }
        }

    } // endCDATA()

    /**
     * The end of the document.
     * @param augs     Additional information that may include infoset augmentations
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void endDocument(Augmentations augs) throws XNIException {

        fInDocument = false;
        if (!fDeferNodeExpansion) {
            // REVISIT: when DOM Level 3 is REC rely on Document.support
            //          instead of specific class
            // set DOM error checking back on
            if (fDocumentImpl != null) {
                fDocumentImpl.setStrictErrorChecking(true);
            }
            fCurrentNode = null;
        }
        else {
            fCurrentNodeIndex = -1;
        }

    } // endDocument()

    /**
     * This method notifies the end of a general entity.
     * <p>
     * <strong>Note:</strong> This method is not called for entity references
     * appearing as part of attribute values.
     *
     * @param name   The name of the entity.                       
     * @param augs   Additional information that may include infoset augmentations
     *              
     * @exception XNIException
     *                   Thrown by handler to signal an error.
     */
    public void endGeneralEntity(String name, Augmentations augs) throws XNIException {
        if (DEBUG_EVENTS) {
            System.out.println("==>endGeneralEntity: ("+name+")");
        }
        if (!fDeferNodeExpansion) {

            if (fFilterReject) {
                return;
            }
            setCharacterData(true);

            if (fDocumentType != null) {
                // get current entity declaration
                NamedNodeMap entities = fDocumentType.getEntities();
                fCurrentEntityDecl = (EntityImpl) entities.getNamedItem(name);
                if (fCurrentEntityDecl != null) {           
                    if (fCurrentEntityDecl != null && fCurrentEntityDecl.getFirstChild() == null) {
                        fCurrentEntityDecl.setReadOnly(false, true);
                        Node child = fCurrentNode.getFirstChild();
                        while (child != null) {
                            Node copy = child.cloneNode(true);
                            fCurrentEntityDecl.appendChild(copy);
                            child = child.getNextSibling();
                         }
                        fCurrentEntityDecl.setReadOnly(true, true);

                        //entities.setNamedItem(fCurrentEntityDecl);
                    }
                    fCurrentEntityDecl = null;
                }

            }

            boolean removeEntityRef = false;
            if (fCreateEntityRefNodes) {
                if (fDocumentImpl != null) {               
                    // Make entity ref node read only
                    ((NodeImpl)fCurrentNode).setReadOnly(true, true);
                }

                if (fDOMFilter !=null &&
                    (fDOMFilter.getWhatToShow() & NodeFilter.SHOW_ENTITY_REFERENCE)!= 0) {
                    short code = fDOMFilter.acceptNode(fCurrentNode);
                    switch (code) {
                        case DOMBuilderFilter.FILTER_INTERRUPT:{
                            throw new RuntimeException("The normal processing of the document was interrupted.");
                        }  
                        case DOMBuilderFilter.FILTER_REJECT:{
                            Node parent = fCurrentNode.getParentNode();
                            parent.removeChild(fCurrentNode);
                            fCurrentNode = parent;
                            return;
                           
                        }
                        case DOMBuilderFilter.FILTER_SKIP: {
                            // make sure we don't loose chars if next event is characters()
                            fFirstChunk = true;
                            removeEntityRef = true;
                            break;
                        }

                        default: {
                            fCurrentNode = fCurrentNode.getParentNode();
                        }
                    }
                } else {
                    fCurrentNode = fCurrentNode.getParentNode();
                }
            }

            if (!fCreateEntityRefNodes || removeEntityRef) {
                // move entity reference children to the list of
                // siblings of its parent and remove entity reference
                NodeList children = fCurrentNode.getChildNodes();
                Node parent = fCurrentNode.getParentNode();
                int length = children.getLength();
                if (length > 0) {
               
                    // get previous sibling of the entity reference
                    Node node = fCurrentNode.getPreviousSibling();
                    // normalize text nodes
                    Node child = children.item(0);
                    if (node != null && node.getNodeType() == Node.TEXT_NODE &&
                        child.getNodeType() == Node.TEXT_NODE) {
                        ((Text)node).appendData(child.getNodeValue());
                        fCurrentNode.removeChild(child);

                    } else {
                        node = parent.insertBefore(child, fCurrentNode);
                        handleBaseURI(node);
                    }

                    for (int i=1;i <length;i++) {
                        node = parent.insertBefore(children.item(0), fCurrentNode);
                        handleBaseURI(node);
                    }
                } // length > 0
                parent.removeChild(fCurrentNode);
                fCurrentNode = parent;
            }
        }
        else {

            if (fDocumentTypeIndex != -1) {
                // find corresponding Entity decl
                int node = fDeferredDocumentImpl.getLastChild(fDocumentTypeIndex, false);
                while (node != -1) {
                    short nodeType = fDeferredDocumentImpl.getNodeType(node, false);
                    if (nodeType == Node.ENTITY_NODE) {
                        String nodeName =
                            fDeferredDocumentImpl.getNodeName(node, false);
                        if (nodeName.equals(name)) {
                            fDeferredEntityDecl = node;
                            break;
                        }
                    }
                    node = fDeferredDocumentImpl.getRealPrevSibling(node, false);
                }
            }

            if (fDeferredEntityDecl != -1 &&
                 fDeferredDocumentImpl.getLastChild(fDeferredEntityDecl, false) == -1) {
                    // entity definition exists and it does not have any children
               int prevIndex = -1;
               int childIndex = fDeferredDocumentImpl.getLastChild(fCurrentNodeIndex, false);
               while (childIndex != -1) {
                   int cloneIndex = fDeferredDocumentImpl.cloneNode(childIndex, true);
                   fDeferredDocumentImpl.insertBefore(fDeferredEntityDecl, cloneIndex, prevIndex);
                   prevIndex = cloneIndex;
                   childIndex = fDeferredDocumentImpl.getRealPrevSibling(childIndex, false);
                }
             }
             if (fCreateEntityRefNodes) {           
                fCurrentNodeIndex =
                     fDeferredDocumentImpl.getParentNode(fCurrentNodeIndex,
                                                         false);
             } else { //!fCreateEntityRefNodes
                 // move children of entity ref before the entity ref.
                 // remove entity ref.
                
                 // holds a child of entity ref
                 int childIndex = fDeferredDocumentImpl.getLastChild(fCurrentNodeIndex, false);
                 int parentIndex =
                     fDeferredDocumentImpl.getParentNode(fCurrentNodeIndex,
                                                         false);
                
                 int prevIndex = fCurrentNodeIndex;
                 int lastChild = childIndex;
                 int sibling = -1;
                 while (childIndex != -1) {
                     handleBaseURI(childIndex);
                     sibling = fDeferredDocumentImpl.getRealPrevSibling(childIndex, false);
                     fDeferredDocumentImpl.insertBefore(parentIndex, childIndex, prevIndex);
                     prevIndex = childIndex;
                     childIndex = sibling;
                 }
                 fDeferredDocumentImpl.setAsLastChild(parentIndex, lastChild);
                 fCurrentNodeIndex = parentIndex;
             }
             fDeferredEntityDecl = -1;
        }
       

    } // endGeneralEntity(String, Augmentations)

   
    /**
     * Record baseURI information for the Element (by adding xml:base attribute)
     * or for the ProcessingInstruction (by setting a baseURI field)
     * Non deferred DOM.
     *
     * @param node
     */
    protected final void handleBaseURI (Node node){
        if (fDocumentImpl != null) {
            // REVISIT: remove dependency on our implementation when
            //          DOM L3 becomes REC
       
            String baseURI = null;
            short nodeType = node.getNodeType();

            if (nodeType == Node.ELEMENT_NODE) {
                // if an element already has xml:base attribute
                // do nothing
                if (fNamespaceAware) {
                    if (((Element)node).getAttributeNodeNS("http://www.w3.org/XML/1998/namespace","base")!=null) {
                        return;
                    }
                } else if (((Element)node).getAttributeNode("xml:base") != null) {
                    return;
                }
                // retrive the baseURI from the entity reference
                baseURI = ((EntityReferenceImpl)fCurrentNode).getBaseURI();
                if (baseURI !=null && !baseURI.equals(fDocumentImpl.getDocumentURI())) {
                    if (fNamespaceAware) {
                        ((Element)node).setAttributeNS("http://www.w3.org/XML/1998/namespace","base", baseURI);
                    } else {
                        ((Element)node).setAttribute("xml:base", baseURI);
                    }
                }
            }
      else if (nodeType == Node.PROCESSING_INSTRUCTION_NODE) {
                           
                baseURI = ((EntityReferenceImpl)fCurrentNode).getBaseURI();
        if (baseURI !=null && fErrorHandler != null) {
          DOMErrorImpl error = new DOMErrorImpl();
                    error.fType = "infoset-baseURI";
                    error.fRelatedData = baseURI;
          error.fSeverity = error.SEVERITY_WARNING;
          fErrorHandler.getErrorHandler().handleError(error);
        }
      }
        }
    }

    /**
     *
     * Record baseURI information for the Element (by adding xml:base attribute)
     * or for the ProcessingInstruction (by setting a baseURI field)
     * Deferred DOM.
     *
     * @param node
     */
    protected final void handleBaseURI (int node){
        short nodeType = fDeferredDocumentImpl.getNodeType(node, false);

        if (nodeType == Node.ELEMENT_NODE) {
            String baseURI = fDeferredDocumentImpl.getNodeValueString(fCurrentNodeIndex, false);
            if (baseURI == null) {
                baseURI = fDeferredDocumentImpl.getDeferredEntityBaseURI(fDeferredEntityDecl);
            }
            if (baseURI !=null && !baseURI.equals(fDeferredDocumentImpl.getDocumentURI())) {
                fDeferredDocumentImpl.setDeferredAttribute(node,
                                                           "xml:base",
                                                           "http://www.w3.org/XML/1998/namespace",
                                                           baseURI,
                                                           true);
            }
        }
    else if (nodeType == Node.PROCESSING_INSTRUCTION_NODE) {


      // retrieve baseURI from the entity reference
      String baseURI = fDeferredDocumentImpl.getNodeValueString(fCurrentNodeIndex, false);

      if (baseURI == null) {
        // try baseURI of the entity declaration
        baseURI = fDeferredDocumentImpl.getDeferredEntityBaseURI(fDeferredEntityDecl);
      }

      if (baseURI != null && fErrorHandler != null) {
        DOMErrorImpl error = new DOMErrorImpl();
        error.fType = "infoset-baseURI";
        error.fRelatedData = baseURI;
                error.fSeverity = error.SEVERITY_WARNING;
        fErrorHandler.getErrorHandler().handleError(error);
      }
    }
    }

                      
    //
    // XMLDTDHandler methods
    //

    /**
     * The start of the DTD.
     *
     * @param locator  The document locator, or null if the document
     *                 location cannot be reported during the parsing of
     *                 the document DTD. However, it is <em>strongly</em>
     *                 recommended that a locator be supplied that can
     *                 at least report the base system identifier of the
     *                 DTD.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void startDTD(XMLLocator locator, Augmentations augs) throws XNIException {
        if (DEBUG_EVENTS) {
            System.out.println("==>startDTD");
            if (DEBUG_BASEURI) {           
                System.out.println("   expandedSystemId: "+locator.getExpandedSystemId());
                System.out.println("   baseURI:"+ locator.getBaseSystemId());
            }
        }

        fInDTD = true;
        if (locator != null) {
            fBaseURIStack.push(locator.getBaseSystemId());
        }
        if (fDeferNodeExpansion || fDocumentImpl != null) {
            fInternalSubset = new StringBuffer(1024);
        }
    } // startDTD(XMLLocator)


    /**
     * The end of the DTD.
     *
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void endDTD(Augmentations augs) throws XNIException {
        if (DEBUG_EVENTS) {
            System.out.println("==>endDTD()");
        }
        fInDTD = false;
        if (!fBaseURIStack.isEmpty()) {
            fBaseURIStack.pop();
        }
        String internalSubset = fInternalSubset != null && fInternalSubset.length() > 0
                              ? fInternalSubset.toString() : null;
        if (fDeferNodeExpansion) {
            if (internalSubset != null) {
                fDeferredDocumentImpl.setInternalSubset(fDocumentTypeIndex, internalSubset);
            }
        }
        else if (fDocumentImpl != null) {
            if (internalSubset != null) {
                ((DocumentTypeImpl)fDocumentType).setInternalSubset(internalSubset);
            }
        }
    } // endDTD()

    /**
     * The start of a conditional section.
     *
     * @param type The type of the conditional section. This value will
     *             either be CONDITIONAL_INCLUDE or CONDITIONAL_IGNORE.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     *
     * @see #CONDITIONAL_INCLUDE
     * @see #CONDITIONAL_IGNORE
     */
    public void startConditional(short type, Augmentations augs) throws XNIException  {
    } // startConditional(short)

    /**
     * The end of a conditional section.
     *
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void endConditional(Augmentations augs) throws XNIException {
    } // endConditional()


    /**
     * The start of the DTD external subset.
     *
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void startExternalSubset(XMLResourceIdentifier identifier,
                                    Augmentations augs) throws XNIException {
        if (DEBUG_EVENTS) {
            System.out.println("==>startExternalSubset");
            if (DEBUG_BASEURI) {           
                System.out.println("   expandedSystemId: "+identifier.getExpandedSystemId());
                System.out.println("   baseURI:"+ identifier.getBaseSystemId());
            }
        }
        fBaseURIStack.push(identifier.getBaseSystemId());
        fInDTDExternalSubset = true;
    } // startExternalSubset(Augmentations)

    /**
     * The end of the DTD external subset.
     *
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void endExternalSubset(Augmentations augs) throws XNIException {
        fInDTDExternalSubset = false;
        fBaseURIStack.pop();
    } // endExternalSubset(Augmentations)

    /**
     * An internal entity declaration.
     *
     * @param name The name of the entity. Parameter entity names start with
     *             '%', whereas the name of a general entity is just the
     *             entity name.
     * @param text The value of the entity.
     * @param nonNormalizedText The non-normalized value of the entity. This
     *             value contains the same sequence of characters that was in
     *             the internal entity declaration, without any entity
     *             references expanded.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void internalEntityDecl(String name, XMLString text,
                                   XMLString nonNormalizedText,
                                   Augmentations augs) throws XNIException {

        if (DEBUG_EVENTS) {
            System.out.println("==>internalEntityDecl: "+name);
            if (DEBUG_BASEURI) {           
                System.out.println("   baseURI:"+ (String)fBaseURIStack.peek());
            }
        } 
        // internal subset string
        if (fInternalSubset != null && !fInDTDExternalSubset) {
            fInternalSubset.append("<!ENTITY ");
            if (name.startsWith("%")) {
                fInternalSubset.append("% ");
                fInternalSubset.append(name.substring(1));
            }
            else {
                fInternalSubset.append(name);
            }
            fInternalSubset.append(' ');
            String value = nonNormalizedText.toString();
            boolean singleQuote = value.indexOf('\'') == -1;
            fInternalSubset.append(singleQuote ? '\'' : '"');
            fInternalSubset.append(value);
            fInternalSubset.append(singleQuote ? '\'' : '"');
            fInternalSubset.append(">\n");
        }

        // NOTE: We only know how to create these nodes for the Xerces
        //       DOM implementation because DOM Level 2 does not specify
        //       that functionality. -Ac

        // create full node
        // don't add parameter entities!
        if(name.startsWith("%"))
            return;
        if (fDocumentType != null) {
            NamedNodeMap entities = fDocumentType.getEntities();
            EntityImpl entity = (EntityImpl)entities.getNamedItem(name);
            if (entity == null) {
                entity = (EntityImpl)fDocumentImpl.createEntity(name);
                entity.setBaseURI((String)fBaseURIStack.peek());
                entities.setNamedItem(entity);
            }
        }
           
        // create deferred node       
        if (fDocumentTypeIndex != -1) {
            boolean found = false;
            int node = fDeferredDocumentImpl.getLastChild(fDocumentTypeIndex, false);
            while (node != -1) {
                short nodeType = fDeferredDocumentImpl.getNodeType(node, false);
                if (nodeType == Node.ENTITY_NODE) {
                    String nodeName = fDeferredDocumentImpl.getNodeName(node, false);
                    if (nodeName.equals(name)) {
                        found = true;
                        break;
                    }
                }
                node = fDeferredDocumentImpl.getRealPrevSibling(node, false);
            }
            if (!found) {
                int entityIndex =
                    fDeferredDocumentImpl.createDeferredEntity(name, null, null, null, (String)fBaseURIStack.peek());
                fDeferredDocumentImpl.appendChild(fDocumentTypeIndex, entityIndex);
            }
        }
   
    } // internalEntityDecl(String,XMLString,XMLString)

    /**
     * An external entity declaration.
     *
     * @param name     The name of the entity. Parameter entity names start
     *                 with '%', whereas the name of a general entity is just
     *                 the entity name.
     * @param identifier    An object containing all location information
     *                      pertinent to this notation.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void externalEntityDecl(String name, XMLResourceIdentifier identifier,
                                   Augmentations augs) throws XNIException {


        if (DEBUG_EVENTS) {
            System.out.println("==>externalEntityDecl: "+name);
            if (DEBUG_BASEURI) {
                System.out.println("   expandedSystemId:"+ identifier.getExpandedSystemId());
                System.out.println("   baseURI:"+ identifier.getBaseSystemId());
            }
        } 
        // internal subset string
        String publicId = identifier.getPublicId();
        String literalSystemId = identifier.getLiteralSystemId();
        if (fInternalSubset != null && !fInDTDExternalSubset) {
            fInternalSubset.append("<!ENTITY ");
            if (name.startsWith("%")) {
                fInternalSubset.append("% ");
                fInternalSubset.append(name.substring(1));
            }
            else {
                fInternalSubset.append(name);
            }
            fInternalSubset.append(' ');
            if (publicId != null) {
                fInternalSubset.append("PUBLIC '");
                fInternalSubset.append(publicId);
                fInternalSubset.append("' '");
            }
            else {
                fInternalSubset.append("SYSTEM '");
            }
            fInternalSubset.append(literalSystemId);
            fInternalSubset.append("'>\n");
        }

        // NOTE: We only know how to create these nodes for the Xerces
        //       DOM implementation because DOM Level 2 does not specify
        //       that functionality. -Ac

        // create full node
        // don't add parameter entities!
        if(name.startsWith("%"))
            return;
        if (fDocumentType != null) {
            NamedNodeMap entities = fDocumentType.getEntities();
            EntityImpl entity = (EntityImpl)entities.getNamedItem(name);
            if (entity == null) {
                entity = (EntityImpl)fDocumentImpl.createEntity(name);
                entity.setPublicId(publicId);
                entity.setSystemId(literalSystemId);
                entity.setBaseURI(identifier.getBaseSystemId());
                entities.setNamedItem(entity);
            }
        }
           
        // create deferred node
        if (fDocumentTypeIndex != -1) {
            boolean found = false;
            int nodeIndex = fDeferredDocumentImpl.getLastChild(fDocumentTypeIndex, false);
            while (nodeIndex != -1) {
                short nodeType = fDeferredDocumentImpl.getNodeType(nodeIndex, false);
                if (nodeType == Node.ENTITY_NODE) {
                    String nodeName = fDeferredDocumentImpl.getNodeName(nodeIndex, false);
                    if (nodeName.equals(name)) {
                        found = true;
                        break;
                    }
                }
                nodeIndex = fDeferredDocumentImpl.getRealPrevSibling(nodeIndex, false);
            }
            if (!found) {
                int entityIndex = fDeferredDocumentImpl.createDeferredEntity(
                                    name, publicId, literalSystemId, null, identifier.getBaseSystemId());
                fDeferredDocumentImpl.appendChild(fDocumentTypeIndex, entityIndex);
            }
        }
   
    } // externalEntityDecl(String,XMLResourceIdentifier, Augmentations)


    /**
     * This method notifies of the start of a parameter entity. The parameter
     * entity name start with a '%' character.
     *
     * @param name     The name of the parameter entity.
     * @param identifier The resource identifier.
     * @param encoding The auto-detected IANA encoding name of the entity
     *                 stream. This value will be null in those situations
     *                 where the entity encoding is not auto-detected (e.g.
     *                 internal parameter entities).
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void startParameterEntity(String name,
                                     XMLResourceIdentifier identifier,
                                     String encoding,
                                     Augmentations augs) throws XNIException {
        if (DEBUG_EVENTS) {
            System.out.println("==>startParameterEntity: "+name);
            if (DEBUG_BASEURI) {           
                System.out.println("   expandedSystemId: "+identifier.getExpandedSystemId());
                System.out.println("   baseURI:"+ identifier.getBaseSystemId());
            }
        } 
        fBaseURIStack.push(identifier.getExpandedSystemId());
    }


    /**
     * This method notifies the end of a parameter entity. Parameter entity
     * names begin with a '%' character.
     *
     * @param name The name of the parameter entity.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void endParameterEntity(String name, Augmentations augs) throws XNIException {
       
        if (DEBUG_EVENTS) {
            System.out.println("==>endParameterEntity: "+name);
        }
        fBaseURIStack.pop();
    }

    /**
     * An unparsed entity declaration.
     *
     * @param name     The name of the entity.
     * @param identifier    An object containing all location information
     *                      pertinent to this entity.
     * @param notation The name of the notation.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void unparsedEntityDecl(String name, XMLResourceIdentifier identifier,
                                   String notation, Augmentations augs)
        throws XNIException {

        if (DEBUG_EVENTS) {
            System.out.println("==>unparsedEntityDecl: "+name);
            if (DEBUG_BASEURI) {
                System.out.println("   expandedSystemId:"+ identifier.getExpandedSystemId());
                System.out.println("   baseURI:"+ identifier.getBaseSystemId());
            }
        } 
        // internal subset string
        String publicId = identifier.getPublicId();
        String literalSystemId = identifier.getLiteralSystemId();
        if (fInternalSubset != null && !fInDTDExternalSubset) {
            fInternalSubset.append("<!ENTITY ");
            fInternalSubset.append(name);
            fInternalSubset.append(' ');
            if (publicId != null) {
                fInternalSubset.append("PUBLIC '");
                fInternalSubset.append(publicId);
                if (literalSystemId != null) {
                    fInternalSubset.append("' '");
                    fInternalSubset.append(literalSystemId);
                }
            }
            else {
                fInternalSubset.append("SYSTEM '");
                fInternalSubset.append(literalSystemId);
            }
            fInternalSubset.append("' NDATA ");
            fInternalSubset.append(notation);
            fInternalSubset.append(">\n");
        }

        // NOTE: We only know how to create these nodes for the Xerces
        //       DOM implementation because DOM Level 2 does not specify
        //       that functionality. -Ac

        // create full node
        if (fDocumentType != null) {
            NamedNodeMap entities = fDocumentType.getEntities();
            EntityImpl entity = (EntityImpl)entities.getNamedItem(name);
            if (entity == null) {
                entity = (EntityImpl)fDocumentImpl.createEntity(name);
                entity.setPublicId(publicId);
                entity.setSystemId(literalSystemId);
                entity.setNotationName(notation);
                entity.setBaseURI(identifier.getBaseSystemId());
                entities.setNamedItem(entity);
            }
        }
           
        // create deferred node       
        if (fDocumentTypeIndex != -1) {
            boolean found = false;
            int nodeIndex = fDeferredDocumentImpl.getLastChild(fDocumentTypeIndex, false);
            while (nodeIndex != -1) {
                short nodeType = fDeferredDocumentImpl.getNodeType(nodeIndex, false);
                if (nodeType == Node.ENTITY_NODE) {
                    String nodeName = fDeferredDocumentImpl.getNodeName(nodeIndex, false);
                    if (nodeName.equals(name)) {
                        found = true;
                        break;
                    }
                }
                nodeIndex = fDeferredDocumentImpl.getRealPrevSibling(nodeIndex, false);
            }
            if (!found) {
                int entityIndex = fDeferredDocumentImpl.createDeferredEntity(
                                    name, publicId, literalSystemId, notation, identifier.getBaseSystemId());
                fDeferredDocumentImpl.appendChild(fDocumentTypeIndex, entityIndex);
            }
        }
   
    } // unparsedEntityDecl(String,XMLResourceIdentifier, String, Augmentations)

    /**
     * A notation declaration
     *
     * @param name     The name of the notation.
     * @param identifier    An object containing all location information
     *                      pertinent to this notation.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void notationDecl(String name, XMLResourceIdentifier identifier,
                             Augmentations augs) throws XNIException {

       // internal subset string
       String publicId = identifier.getPublicId();
       String literalSystemId = identifier.getLiteralSystemId();
       if (fInternalSubset != null && !fInDTDExternalSubset) {
        fInternalSubset.append("<!NOTATION ");
        fInternalSubset.append(name);
        if (publicId != null) {
          fInternalSubset.append(" PUBLIC '");
          fInternalSubset.append(publicId);
          if (literalSystemId != null) {
            fInternalSubset.append("' '");
            fInternalSubset.append(literalSystemId);
          }
        }
        else {
          fInternalSubset.append(" SYSTEM '");
          fInternalSubset.append(literalSystemId);
        }
        fInternalSubset.append("'>\n");
       }

        // NOTE: We only know how to create these nodes for the Xerces
        //       DOM implementation because DOM Level 2 does not specify
        //       that functionality. -Ac

        // create full node
        if (fDocumentImpl !=null && fDocumentType != null) {
            NamedNodeMap notations = fDocumentType.getNotations();
            if (notations.getNamedItem(name) == null) {
                NotationImpl notation = (NotationImpl)fDocumentImpl.createNotation(name);
                notation.setPublicId(publicId);
                notation.setSystemId(literalSystemId);
                notation.setBaseURI(identifier.getBaseSystemId());
                notations.setNamedItem(notation);
            }
        }

        // create deferred node
        if (fDocumentTypeIndex != -1) {
            boolean found = false;
            int nodeIndex = fDeferredDocumentImpl.getLastChild(fDocumentTypeIndex, false);
            while (nodeIndex != -1) {
                short nodeType = fDeferredDocumentImpl.getNodeType(nodeIndex, false);
                if (nodeType == Node.NOTATION_NODE) {
                    String nodeName = fDeferredDocumentImpl.getNodeName(nodeIndex, false);
                    if (nodeName.equals(name)) {
                        found = true;
                        break;
                    }
                }
                nodeIndex = fDeferredDocumentImpl.getPrevSibling(nodeIndex, false);
            }
            if (!found) {
                int notationIndex = fDeferredDocumentImpl.createDeferredNotation(
                                        name, publicId, literalSystemId, identifier.getBaseSystemId());
                fDeferredDocumentImpl.appendChild(fDocumentTypeIndex, notationIndex);
            }
        }

    } // notationDecl(String,XMLResourceIdentifier, Augmentations)

    /**
     * Characters within an IGNORE conditional section.
     *
     * @param text The ignored text.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
     public void ignoredCharacters(XMLString text, Augmentations augs) throws XNIException {
     } // ignoredCharacters(XMLString, Augmentations)


    /**
     * An element declaration.
     *
     * @param name         The name of the element.
     * @param contentModel The element content model.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void elementDecl(String name, String contentModel, Augmentations augs)
        throws XNIException {

        // internal subset string
        if (fInternalSubset != null && !fInDTDExternalSubset) {
            fInternalSubset.append("<!ELEMENT ");
            fInternalSubset.append(name);
            fInternalSubset.append(' ');
            fInternalSubset.append(contentModel);
            fInternalSubset.append(">\n");
        }

    } // elementDecl(String,String)

    /**
     * An attribute declaration.
     *
     * @param elementName   The name of the element that this attribute
     *                      is associated with.
     * @param attributeName The name of the attribute.
     * @param type          The attribute type. This value will be one of
     *                      the following: "CDATA", "ENTITY", "ENTITIES",
     *                      "ENUMERATION", "ID", "IDREF", "IDREFS",
     *                      "NMTOKEN", "NMTOKENS", or "NOTATION".
     * @param enumeration   If the type has the value "ENUMERATION" or
     *                      "NOTATION", this array holds the allowed attribute
     *                      values; otherwise, this array is null.
     * @param defaultType   The attribute default type. This value will be
     *                      one of the following: "#FIXED", "#IMPLIED",
     *                      "#REQUIRED", or null.
     * @param defaultValue  The attribute default value, or null if no
     *                      default value is specified.
     * @param nonNormalizedDefaultValue  The attribute default value with no normalization
     *                      performed, or null if no default value is specified.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void attributeDecl(String elementName, String attributeName,
                              String type, String[] enumeration,
                              String defaultType, XMLString defaultValue,
                              XMLString nonNormalizedDefaultValue, Augmentations augs) throws XNIException {

        // internal subset string
        if (fInternalSubset != null && !fInDTDExternalSubset) {
            fInternalSubset.append("<!ATTLIST ");
            fInternalSubset.append(elementName);
            fInternalSubset.append(' ');
            fInternalSubset.append(attributeName);
            fInternalSubset.append(' ');
            if (type.equals("ENUMERATION")) {
                fInternalSubset.append('(');
                for (int i = 0; i < enumeration.length; i++) {
                    if (i > 0) {
                        fInternalSubset.append('|');
                    }
                    fInternalSubset.append(enumeration[i]);
                }
                fInternalSubset.append(')');
            }
            else {
                fInternalSubset.append(type);
            }
            if (defaultType != null) {
                fInternalSubset.append(' ');
                fInternalSubset.append(defaultType);
            }
            if (defaultValue != null) {
                fInternalSubset.append(" '");
                for (int i = 0; i < defaultValue.length; i++) {
                    char c = defaultValue.ch[defaultValue.offset + i];
                    if (c == '\'') {
                        fInternalSubset.append("&apos;");
                    }
                    else {
                        fInternalSubset.append(c);
                    }
                }
                fInternalSubset.append('\'');
            }
            fInternalSubset.append(">\n");
        }
        // REVISIT: This code applies to the support of domx/grammar-access
        // feature in Xerces 1
        // deferred expansion
        if (fDeferredDocumentImpl != null) {

            // get the default value
            if (defaultValue != null) {

                // get element definition
                int elementDefIndex  = fDeferredDocumentImpl.lookupElementDefinition(elementName);

                // create element definition if not already there
                if (elementDefIndex == -1) {
                    elementDefIndex = fDeferredDocumentImpl.createDeferredElementDefinition(elementName);
                    fDeferredDocumentImpl.appendChild(fDocumentTypeIndex, elementDefIndex);
                }
                // add default attribute
                int attrIndex = fDeferredDocumentImpl.createDeferredAttribute(
                                    attributeName, defaultValue.toString(), false);
                if (type.equals("ID")) {              
                    fDeferredDocumentImpl.setIdAttribute(attrIndex);
                }
                // REVISIT: set ID type correctly
                fDeferredDocumentImpl.appendChild(elementDefIndex, attrIndex);
            }

        } // if deferred

        // full expansion
        else if (fDocumentImpl != null) {

            // get the default value
            if (defaultValue != null) {

                // get element definition node
                NamedNodeMap elements = ((DocumentTypeImpl)fDocumentType).getElements();
                ElementDefinitionImpl elementDef = (ElementDefinitionImpl)elements.getNamedItem(elementName);
                if (elementDef == null) {
                    elementDef = fDocumentImpl.createElementDefinition(elementName);
                    ((DocumentTypeImpl)fDocumentType).getElements().setNamedItem(elementDef);
                }

                // REVISIT: Check for uniqueness of element name? -Ac

                // create attribute and set properties
                boolean nsEnabled = fNamespaceAware;
                AttrImpl attr;
                if (nsEnabled) {
                    String namespaceURI = null;
                    // DOM Level 2 wants all namespace declaration attributes
                    // to be bound to "http://www.w3.org/2000/xmlns/"
                    // So as long as the XML parser doesn't do it, it needs to
                    // done here.
                    if (attributeName.startsWith("xmlns:") ||
                        attributeName.equals("xmlns")) {
                        namespaceURI = NamespaceContext.XMLNS_URI;
                    }
                    attr = (AttrImpl)fDocumentImpl.createAttributeNS(namespaceURI,
                                                                attributeName);
                }
                else {
                    attr = (AttrImpl)fDocumentImpl.createAttribute(attributeName);
                }
                attr.setValue(defaultValue.toString());
                attr.setSpecified(false);
                attr.setIdAttribute(type.equals("ID"));

                // add default attribute to element definition
                if (nsEnabled){
                    elementDef.getAttributes().setNamedItemNS(attr);
                }
                else {
                    elementDef.getAttributes().setNamedItem(attr);
                }
            }

        } // if NOT defer-node-expansion
     
    } // attributeDecl(String,String,String,String[],String,XMLString, XMLString, Augmentations)


    /**
     * The start of an attribute list.
     *
     * @param elementName The name of the element that this attribute
     *                    list is associated with.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void startAttlist(String elementName, Augmentations augs) throws XNIException {
    } // startAttlist(String)


    /**
     * The end of an attribute list.
     *
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void endAttlist(Augmentations augs) throws XNIException {
    } // endAttlist()


    // method to create an element node.
    // subclasses can override this method to create element nodes in other ways.
    protected Element createElementNode(QName element) {
        Element el = null;
       
        if (fNamespaceAware) {
            // if we are using xerces DOM implementation, call our
            // own constructor to reuse the strings we have here.
            if (fDocumentImpl != null) {
                el = fDocumentImpl.createElementNS(element.uri, element.rawname,
                                                   element.localpart);
            }
            else {
                el = fDocument.createElementNS(element.uri, element.rawname);
            }
        }
        else {
            el = fDocument.createElement(element.rawname);
        }
       
        return el;
    }

    // method to create an attribute node.
    // subclasses can override this method to create attribute nodes in other ways.
    protected Attr createAttrNode(QName attrQName) {
        Attr attr = null;
       
        if (fNamespaceAware) {
            if (fDocumentImpl != null) {
                // if we are using xerces DOM implementation, call our
                // own constructor to reuse the strings we have here.
                attr = fDocumentImpl.createAttributeNS(attrQName.uri,
                                                       attrQName.rawname,
                                                       attrQName.localpart);
            }
            else {
                attr = fDocument.createAttributeNS(attrQName.uri,
                                                   attrQName.rawname);
            }
        }
        else {
            attr = fDocument.createAttribute(attrQName.rawname);
        }
       
        return attr;
    }

    /*
     * When the first characters() call is received, the data is stored in
     * a new Text node. If right after the first characters() we receive another chunk of data,
     * the data from the Text node, following the new characters are appended
     * to the fStringBuffer and the text node data is set to empty.
     *
     * This function is called when the state is changed and the
     * data must be appended to the current node.
     *
     * Note: if DOMFilter is set, you must make sure that if Node is skipped,
     * or removed fFistChunk must be set to true, otherwise some data can be lost.    
     *
     */
    protected void  setCharacterData(boolean sawChars){

        // handle character data
        fFirstChunk = sawChars;
       

        // if we have data in the buffer we must have created
        // a text node already.
      
        Node child = fCurrentNode.getLastChild();
        if (child != null) {       
            if (fStringBuffer.length() > 0) {
                // REVISIT: should this check be performed?
                if (child.getNodeType() == Node.TEXT_NODE) {
                    if (fDocumentImpl != null) {
                        ((TextImpl)child).replaceData(fStringBuffer.toString());
                    }
                    else {
                        ((Text)child).setData(fStringBuffer.toString());
                    }
                }
                // reset string buffer
                fStringBuffer.setLength(0);
            }

            if (fDOMFilter !=null) {
                if ((fDOMFilter.getWhatToShow() & NodeFilter.SHOW_TEXT)!= 0) {
                    short code = fDOMFilter.acceptNode(child);
                    switch (code) {
                        case DOMBuilderFilter.FILTER_INTERRUPT:{
                            throw new RuntimeException("The normal processing of the document was interrupted.");
                        }  
                        case DOMBuilderFilter.FILTER_REJECT:{
                            // fall through to SKIP since Comment has no children.
                        }
                        case DOMBuilderFilter.FILTER_SKIP: {
                            fCurrentNode.removeChild(child);
                            return;
                        }
                        default: {
                            // accept node -- do nothing
                        }
                    }
                }
            }   // end-if fDOMFilter !=null

        } // end-if child !=null
    }
   
   
    /**
     * @see org.w3c.dom.ls.DOMBuilder#abort()
     */
    public void abort() {
           throw new RuntimeException();
    }

   
} // class AbstractDOMParser
TOP

Related Classes of org.apache.xerces.parsers.AbstractDOMParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.