All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.xerces.parsers.AbstractDOMParser Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

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.DOMMessageFormatter;
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.PSVIDocumentImpl;
import org.apache.xerces.dom.PSVIElementNSImpl;
import org.apache.xerces.dom.TextImpl;
import org.apache.xerces.impl.Constants;
import org.apache.xerces.impl.dv.XSSimpleType;
import org.apache.xerces.util.DOMErrorHandlerWrapper;
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.xs.AttributePSVI;
import org.apache.xerces.xs.ElementPSVI;
import org.apache.xerces.xs.XSTypeDefinition;
import org.w3c.dom.Attr;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Comment;
import org.w3c.dom.DOMError;
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.LSParserFilter;
import org.w3c.dom.traversal.NodeFilter;
import org.xml.sax.SAXException;

/**
 * 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
 * getDocument 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 782187 2009-06-06 04:21:12Z mrglavas $
 */
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";

    /**
     * If the user stops the process, this exception will be thrown.
     */
    static final class Abort extends RuntimeException {
        private static final long serialVersionUID = 1687848994976808490L;
        static final Abort INSTANCE = new Abort();
        private Abort() {}
        public Throwable fillInStackTrace() {
            return this;
        }
    }

    // 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;

    /** Root element node. */
    protected Node fRoot;

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

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


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

    // data

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

    /** LSParserFilter: tracks the element depth within a rejected subtree. */
    protected int fRejectedElementDepth = 0;

    /** LSParserFilter: store depth of skipped elements */
    protected Stack fSkippedElemStack = null;

    /** LSParserFilter: true if inside entity reference */
    protected boolean fInEntityRef = false;

    /** Attribute QName. */
    private final QName fAttrQName = new QName();
    
    /** Document locator. */
    private XMLLocator fLocator;

    // handlers

    protected LSParserFilter 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);

    } // (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;
        }

        if (!documentClassName.equals(DEFAULT_DOCUMENT_CLASS_NAME) &&
            !documentClassName.equals(PSVI_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)) {
                    throw new IllegalArgumentException (
                        DOMMessageFormatter.formatMessage(
                        DOMMessageFormatter.DOM_DOMAIN,
                        "InvalidDocumentClassName", new Object [] {documentClassName}));
                }
            }
            catch (ClassNotFoundException e) {
                throw new IllegalArgumentException (
                    DOMMessageFormatter.formatMessage(
                    DOMMessageFormatter.DOM_DOMAIN,
                    "MissingDocumentClassName", new Object [] {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
    
    /** 
     * Drops all references to the last DOM which was built by this parser.
     */
    public final void dropDocumentReferences() {
        fDocument = null;
        fDocumentImpl = null;
        fDeferredDocumentImpl = null;
        fDocumentType = null;
        fCurrentNode = null;
        fCurrentCDATASection = null;
        fCurrentEntityDecl = null;
        fRoot = null;
    } // dropDocumentReferences()

    //
    // 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
        fRoot = null;
        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.
     * 

* Note: 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.setInputEncoding (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); } fInEntityRef = true; 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.setInputEncoding (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. *

* Note: This method will never be called for the * document entity; it is only called for external general entities * referenced in document content. *

* Note: 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.setXmlEncoding (encoding); if (version != null) fCurrentEntityDecl.setXmlVersion (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 (""); } return; } if (!fIncludeComments || fFilterReject) { return; } if (!fDeferNodeExpansion) { Comment comment = fDocument.createComment (text.toString ()); setCharacterData (false); fCurrentNode.appendChild (comment); if (fDOMFilter !=null && !fInEntityRef && (fDOMFilter.getWhatToShow () & NodeFilter.SHOW_COMMENT)!= 0) { short code = fDOMFilter.acceptNode (comment); switch (code) { case LSParserFilter.FILTER_INTERRUPT:{ throw Abort.INSTANCE; } case LSParserFilter.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 LSParserFilter.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. *

* Typically, a processing instruction's data will contain a series * of pseudo-attributes. These pseudo-attributes follow the form of * element attributes but are not 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 (" 0) { fInternalSubset.append (' ').append (data.ch, data.offset, data.length); } 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 && !fInEntityRef && (fDOMFilter.getWhatToShow () & NodeFilter.SHOW_PROCESSING_INSTRUCTION)!= 0) { short code = fDOMFilter.acceptNode (pi); switch (code) { case LSParserFilter.FILTER_INTERRUPT:{ throw Abort.INSTANCE; } case LSParserFilter.FILTER_REJECT:{ // fall through to SKIP since PI has no children. } case LSParserFilter.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 { fLocator = locator; 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.setInputEncoding (encoding); // set documentURI fDocumentImpl.setDocumentURI (locator.getExpandedSystemId ()); } else if (fDocumentClassName.equals (PSVI_DOCUMENT_CLASS_NAME)) { fDocument = new PSVIDocumentImpl(); fDocumentImpl = (CoreDocumentImpl)fDocument; 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.setInputEncoding (encoding); // set documentURI fDocumentImpl.setDocumentURI (locator.getExpandedSystemId ()); } else { // use specified document class try { ClassLoader cl = ObjectFactory.findClassLoader(); Class documentClass = ObjectFactory.findProviderClass (fDocumentClassName, cl, true); fDocument = (Document)documentClass.newInstance (); // if subclass of our own class that's cool too Class defaultDocClass = ObjectFactory.findProviderClass (CORE_DOCUMENT_CLASS_NAME, cl, true); if (defaultDocClass.isAssignableFrom (documentClass)) { fDocumentImpl = (CoreDocumentImpl)fDocument; Class psviDocClass = ObjectFactory.findProviderClass (PSVI_DOCUMENT_CLASS_NAME, cl, 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.setInputEncoding (encoding); // set documentURI if (locator != null) { fDocumentImpl.setDocumentURI (locator.getExpandedSystemId ()); } } } catch (ClassNotFoundException e) { // won't happen we already checked that earlier } catch (Exception e) { throw new RuntimeException ( DOMMessageFormatter.formatMessage( DOMMessageFormatter.DOM_DOMAIN, "CannotCreateDocumentClass", new Object [] {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.setInputEncoding (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) { if (version != null) fDocumentImpl.setXmlVersion (version); fDocumentImpl.setXmlEncoding (encoding); fDocumentImpl.setXmlStandalone ("yes".equals (standalone)); } } else { if (version != null) fDeferredDocumentImpl.setXmlVersion (version); fDeferredDocumentImpl.setXmlEncoding (encoding); fDeferredDocumentImpl.setXmlStandalone ("yes".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) { ++fRejectedElementDepth; return; } Element el = createElementNode (element); int attrCount = attributes.getLength (); boolean seenSchemaDefault = false; 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); boolean specified = attributes.isSpecified(i); // Take special care of schema defaulted attributes. Calling the // non-namespace aware setAttributeNode() method could overwrite // another attribute with the same local name. if (!specified && (seenSchemaDefault || (fAttrQName.uri != null && fAttrQName.uri != NamespaceContext.XMLNS_URI && fAttrQName.prefix == null))) { el.setAttributeNodeNS(attr); seenSchemaDefault = true; } else { 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 boolean isDeclared = Boolean.TRUE.equals (attributes.getAugmentations (i).getItem (Constants.ATTRIBUTE_DECLARED)); // For DOM Level 3 TypeInfo, the type name must // be null if this attribute has not been declared // in the DTD. if (isDeclared) { type = attributes.getType (i); id = "ID".equals (type); } attrImpl.setType (type); } if (id) { ((ElementImpl) el).setIdAttributeNode (attr, true); } attrImpl.setSpecified (specified); // 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 && !fInEntityRef) { if (fRoot == null) { // fill value of the root element fRoot = el; } else { short code = fDOMFilter.startElement(el); switch (code) { case LSParserFilter.FILTER_INTERRUPT : { throw Abort.INSTANCE; } case LSParserFilter.FILTER_REJECT : { fFilterReject = true; fRejectedElementDepth = 0; return; } case LSParserFilter.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 lose it). fFirstChunk = true; fSkippedElemStack.push(Boolean.TRUE); return; } default : { if (!fSkippedElemStack.isEmpty()) { fSkippedElemStack.push(Boolean.FALSE); } } } } } fCurrentNode.appendChild (el); fCurrentNode = el; } else { int el = fDeferredDocumentImpl.createDeferredElement (fNamespaceAware ? element.uri : null, element.rawname); Object type = null; int attrCount = attributes.getLength (); // Need to loop in reverse order so that the attributes // are processed in document order when the DOM is expanded. for (int i = attrCount - 1; i >= 0; --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 boolean isDeclared = Boolean.TRUE.equals (attributes.getAugmentations (i).getItem (Constants.ATTRIBUTE_DECLARED)); // For DOM Level 3 TypeInfo, the type name must // be null if this attribute has not been declared // in the DTD. if (isDeclared) { type = attributes.getType (i); id = "ID".equals (type); } } // 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; } 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; } if (text.length > 0) { fStringBuffer.append (text.ch, text.offset, text.length); } } else { fFirstChunk = true; Text textNode = fDocument.createTextNode (text.toString()); 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 (augs != null && fDocumentImpl != null && (fNamespaceAware || fStorePSVI)) { ElementPSVI elementPSVI = (ElementPSVI) augs.getItem(Constants.ELEMENT_PSVI); if (elementPSVI != null) { // Updating TypeInfo. If the declared type is a union the // [member type definition] will only be available at the // end of an element. if (fNamespaceAware) { XSTypeDefinition type = elementPSVI.getMemberTypeDefinition(); if (type == null) { type = elementPSVI.getTypeDefinition(); } ((ElementNSImpl)fCurrentNode).setType(type); } if (fStorePSVI) { ((PSVIElementNSImpl)fCurrentNode).setPSVI (elementPSVI); } } } if (fDOMFilter != null) { if (fFilterReject) { if (fRejectedElementDepth-- == 0) { fFilterReject = false; } return; } if (!fSkippedElemStack.isEmpty()) { if (fSkippedElemStack.pop() == Boolean.TRUE) { return; } } setCharacterData (false); if ((fCurrentNode != fRoot) && !fInEntityRef && (fDOMFilter.getWhatToShow () & NodeFilter.SHOW_ELEMENT)!=0) { short code = fDOMFilter.acceptNode (fCurrentNode); switch (code) { case LSParserFilter.FILTER_INTERRUPT:{ throw Abort.INSTANCE; } case LSParserFilter.FILTER_REJECT:{ Node parent = fCurrentNode.getParentNode (); parent.removeChild (fCurrentNode); fCurrentNode = parent; return; } case LSParserFilter.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 lose it). fFirstChunk = true; // replace children Node parent = fCurrentNode.getParentNode (); NodeList ls = fCurrentNode.getChildNodes (); int length = ls.getLength (); for (int i=0;i * Note: 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; } } fInEntityRef = false; 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 LSParserFilter.FILTER_INTERRUPT:{ throw Abort.INSTANCE; } case LSParserFilter.FILTER_REJECT:{ Node parent = fCurrentNode.getParentNode (); parent.removeChild (fCurrentNode); fCurrentNode = parent; return; } case LSParserFilter.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 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; } if(lastChild != -1) fDeferredDocumentImpl.setAsLastChild (parentIndex, lastChild); else{ sibling = fDeferredDocumentImpl.getRealPrevSibling (prevIndex, false); fDeferredDocumentImpl.setAsLastChild (parentIndex, sibling); } 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", "xml: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 = "pi-base-uri-not-preserved"; error.fRelatedData = baseURI; error.fSeverity = DOMError.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 = "pi-base-uri-not-preserved"; error.fRelatedData = baseURI; error.fSeverity = DOMError.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 strongly * 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 ("\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 ("\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 ()); } } if (augs != null && fInternalSubset != null && !fInDTDExternalSubset && Boolean.TRUE.equals(augs.getItem(Constants.ENTITY_SKIPPED))) { fInternalSubset.append(name).append(";\n"); } 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 ("\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 ("\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 ("\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 (" 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 ("'"); } 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 boolean nsEnabled = fNamespaceAware; String namespaceURI = null; if (nsEnabled) { // 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; } else if (attributeName.startsWith("xml:")) { namespaceURI = NamespaceContext.XML_URI; } } int attrIndex = fDeferredDocumentImpl.createDeferredAttribute ( attributeName, namespaceURI, defaultValue.toString(), false); if ("ID".equals (type)) { 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; } else if (attributeName.startsWith("xml:")) { namespaceURI = NamespaceContext.XML_URI; } attr = (AttrImpl)fDocumentImpl.createAttributeNS (namespaceURI, attributeName); } else { attr = (AttrImpl)fDocumentImpl.createAttribute (attributeName); } attr.setValue (defaultValue.toString ()); attr.setSpecified (false); attr.setIdAttribute ("ID".equals (type)); // 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 && !fInEntityRef) { if ( (child.getNodeType () == Node.TEXT_NODE ) && ((fDOMFilter.getWhatToShow () & NodeFilter.SHOW_TEXT)!= 0) ) { short code = fDOMFilter.acceptNode (child); switch (code) { case LSParserFilter.FILTER_INTERRUPT:{ throw Abort.INSTANCE; } case LSParserFilter.FILTER_REJECT:{ // fall through to SKIP since Comment has no children. } case LSParserFilter.FILTER_SKIP: { fCurrentNode.removeChild (child); return; } default: { // accept node -- do nothing } } } } // end-if fDOMFilter !=null } // end-if child !=null } /** * @see org.w3c.dom.ls.LSParser#abort() */ public void abort () { throw Abort.INSTANCE; } } // class AbstractDOMParser





© 2015 - 2024 Weber Informatics LLC | Privacy Policy