jaxp/src/com/sun/org/apache/xerces/internal/impl/XMLNSDocumentScannerImpl.java
changeset 12457 c348e06f0e82
parent 12005 a754d69d5e60
child 20968 dde41f8b7b96
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/com/sun/org/apache/xerces/internal/impl/XMLNSDocumentScannerImpl.java	Thu Apr 12 08:38:26 2012 -0700
@@ -0,0 +1,637 @@
+/*
+ * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed 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 com.sun.org.apache.xerces.internal.impl;
+
+import java.io.IOException;
+import com.sun.org.apache.xerces.internal.xni.XMLString;
+import com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidatorFilter;
+import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
+import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
+import com.sun.org.apache.xerces.internal.util.XMLAttributesIteratorImpl;
+import com.sun.org.apache.xerces.internal.util.XMLStringBuffer;
+import com.sun.org.apache.xerces.internal.util.XMLSymbols;
+import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
+import com.sun.org.apache.xerces.internal.xni.QName;
+import com.sun.org.apache.xerces.internal.xni.XNIException;
+import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
+import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
+import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
+import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
+import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
+import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.events.XMLEvent;
+
+/**
+ * This class adds the functionality of namespace processing.
+ *
+ * This class has been modified as per the new design which is more suited to
+ * efficiently build pull parser. Lot of improvements have been done and
+ * the code has been added to support stax functionality/features.
+ *
+ *
+ * This class scans an XML document, checks if document has a DTD, and if
+ * DTD is not found the scanner will remove the DTD Validator from the pipeline and perform
+ * namespace binding.
+ *
+ *
+ * @author Neeraj Bajaj, Sun Microsystems
+ * @author Venugopal Rao K, Sun Microsystems
+ * @author Elena Litani, IBM
+ */
+public class XMLNSDocumentScannerImpl
+        extends XMLDocumentScannerImpl {
+
+    /**
+     * If is true, the dtd validator is no longer in the pipeline
+     * and the scanner should bind namespaces
+     */
+    protected boolean fBindNamespaces;
+
+    /** If validating parser, make sure we report an error in the
+     *   scanner if DTD grammar is missing.*/
+    protected boolean fPerformValidation;
+
+
+    /** Default value of this feature is false, when in Stax mode this should be true */
+    protected boolean fNotAddNSDeclAsAttribute = false;
+
+    /** DTD validator */
+     private XMLDTDValidatorFilter fDTDValidator;
+
+     /** xmlns, default Namespace, declared */
+     private boolean fXmlnsDeclared = false;
+
+    /** Resets the fields of this scanner.
+     */
+    public void reset(PropertyManager propertyManager) {
+        setPropertyManager(propertyManager);
+        super.reset(propertyManager);
+        fBindNamespaces = false;
+        fNotAddNSDeclAsAttribute = !((Boolean)propertyManager.getProperty(Constants.ADD_NAMESPACE_DECL_AS_ATTRIBUTE)).booleanValue();
+    }
+
+    public void reset(XMLComponentManager componentManager)
+    throws XMLConfigurationException {
+        super.reset(componentManager);
+        fNotAddNSDeclAsAttribute = false ;
+        fPerformValidation = false;
+        fBindNamespaces = false;
+    }
+
+    /** return the next state on the input
+     *
+     * @return int
+     */
+
+    public int next() throws IOException, XNIException {
+        //since namespace context should still be valid when the parser is at the end element state therefore
+        //we pop the context only when next() has been called after the end element state was encountered. - nb.
+
+        if((fScannerLastState == XMLEvent.END_ELEMENT) && fBindNamespaces){
+            fScannerLastState = -1;
+            fNamespaceContext.popContext();
+        }
+
+        return fScannerLastState = super.next();
+    }
+
+    /**
+     * The scanner is responsible for removing DTD validator
+     * from the pipeline if it is not needed.
+     *
+     * @param previous The filter component before DTDValidator
+     * @param dtdValidator
+     *                 The DTDValidator
+     * @param next     The documentHandler after the DTDValidator
+     */
+    public void setDTDValidator(XMLDTDValidatorFilter dtd){
+        fDTDValidator = dtd;
+    }
+
+
+
+    /**
+     * Scans a start element. This method will handle the binding of
+     * namespace information and notifying the handler of the start
+     * of the element.
+     * <p>
+     * <pre>
+     * [44] EmptyElemTag ::= '&lt;' Name (S Attribute)* S? '/>'
+     * [40] STag ::= '&lt;' Name (S Attribute)* S? '>'
+     * </pre>
+     * <p>
+     * <strong>Note:</strong> This method assumes that the leading
+     * '&lt;' character has been consumed.
+     * <p>
+     * <strong>Note:</strong> This method uses the fElementQName and
+     * fAttributes variables. The contents of these variables will be
+     * destroyed. The caller should copy important information out of
+     * these variables before calling this method.
+     *
+     * @return True if element is empty. (i.e. It matches
+     *          production [44].
+     */
+    protected boolean scanStartElement()
+    throws IOException, XNIException {
+
+        if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +">>> scanStartElement()");
+        //when skipping is true and no more elements should be added
+        if(fSkip && !fAdd){
+            //get the stored element -- if everything goes right this should match the
+            //token in the buffer
+
+            QName name = fElementStack.getNext();
+
+            if(DEBUG_SKIP_ALGORITHM){
+                System.out.println("Trying to skip String = " + name.rawname);
+            }
+
+            //Be conservative -- if skipping fails -- stop.
+            fSkip = fEntityScanner.skipString(name.rawname); // skipQElement(name);
+
+            if(fSkip){
+                if(DEBUG_SKIP_ALGORITHM){
+                    System.out.println("Element SUCESSFULLY skipped = " + name.rawname);
+                }
+                fElementStack.push();
+                fElementQName = name;
+            }else{
+                //if skipping fails reposition the stack or fallback to normal way of processing
+                fElementStack.reposition();
+                if(DEBUG_SKIP_ALGORITHM){
+                    System.out.println("Element was NOT skipped, REPOSITIONING stack" );
+                }
+            }
+        }
+
+        //we are still at the stage of adding elements
+        //the elements were not matched or
+        //fSkip is not set to true
+        if(!fSkip || fAdd){
+            //get the next element from the stack
+            fElementQName = fElementStack.nextElement();
+            // There are two variables,fNamespaces and fBindNamespaces
+            //StAX uses XMLNSDocumentScannerImpl so this distinction needs to be maintained
+            if (fNamespaces) {
+                fEntityScanner.scanQName(fElementQName);
+            } else {
+                String name = fEntityScanner.scanName();
+                fElementQName.setValues(null, name, name, null);
+            }
+
+            if(DEBUG)System.out.println("Element scanned in start element is " + fElementQName.toString());
+            if(DEBUG_SKIP_ALGORITHM){
+                if(fAdd){
+                    System.out.println("Elements are being ADDED -- elemet added is = " + fElementQName.rawname + " at count = " + fElementStack.fCount);
+                }
+            }
+
+        }
+
+        //when the elements are being added , we need to check if we are set for skipping the elements
+        if(fAdd){
+            //this sets the value of fAdd variable
+            fElementStack.matchElement(fElementQName);
+        }
+
+        //xxx: We dont need another pointer, fCurrentElement, we can use fElementQName
+        fCurrentElement = fElementQName;
+
+        String rawname = fElementQName.rawname;
+        if (fBindNamespaces) {
+            fNamespaceContext.pushContext();
+            if (fScannerState == SCANNER_STATE_ROOT_ELEMENT) {
+                if (fPerformValidation) {
+                    fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
+                            "MSG_GRAMMAR_NOT_FOUND",
+                            new Object[]{ rawname},
+                            XMLErrorReporter.SEVERITY_ERROR);
+
+                            if (fDoctypeName == null || !fDoctypeName.equals(rawname)) {
+                                fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,
+                                        "RootElementTypeMustMatchDoctypedecl",
+                                        new Object[]{fDoctypeName, rawname},
+                                        XMLErrorReporter.SEVERITY_ERROR);
+                            }
+                }
+            }
+        }
+
+
+        fEmptyElement = false;
+        fAttributes.removeAllAttributes();
+
+        if(!seekCloseOfStartTag()){
+            fReadingAttributes = true;
+            fAttributeCacheUsedCount =0;
+            fStringBufferIndex =0;
+            fAddDefaultAttr = true;
+            fXmlnsDeclared = false;
+
+            do {
+                scanAttribute(fAttributes);
+                if (fSecurityManager != null && fAttributes.getLength() > fElementAttributeLimit){
+                    fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
+                                                 "ElementAttributeLimit",
+                                                 new Object[]{rawname, new Integer(fAttributes.getLength()) },
+                                                 XMLErrorReporter.SEVERITY_FATAL_ERROR );
+                }
+
+            } while (!seekCloseOfStartTag());
+            fReadingAttributes=false;
+        }
+
+        if (fBindNamespaces) {
+            // REVISIT: is it required? forbit xmlns prefix for element
+            if (fElementQName.prefix == XMLSymbols.PREFIX_XMLNS) {
+                fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
+                        "ElementXMLNSPrefix",
+                        new Object[]{fElementQName.rawname},
+                        XMLErrorReporter.SEVERITY_FATAL_ERROR);
+            }
+
+            // bind the element
+            String prefix = fElementQName.prefix != null
+                    ? fElementQName.prefix : XMLSymbols.EMPTY_STRING;
+            // assign uri to the element
+            fElementQName.uri = fNamespaceContext.getURI(prefix);
+            // make sure that object in the element stack is updated as well
+            fCurrentElement.uri = fElementQName.uri;
+
+            if (fElementQName.prefix == null && fElementQName.uri != null) {
+                fElementQName.prefix = XMLSymbols.EMPTY_STRING;
+            }
+            if (fElementQName.prefix != null && fElementQName.uri == null) {
+                fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
+                        "ElementPrefixUnbound",
+                        new Object[]{fElementQName.prefix, fElementQName.rawname},
+                        XMLErrorReporter.SEVERITY_FATAL_ERROR);
+            }
+
+            // bind attributes (xmlns are already bound bellow)
+            int length = fAttributes.getLength();
+            // fLength = 0; //initialize structure
+            for (int i = 0; i < length; i++) {
+                fAttributes.getName(i, fAttributeQName);
+
+                String aprefix = fAttributeQName.prefix != null
+                        ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
+                String uri = fNamespaceContext.getURI(aprefix);
+                // REVISIT: try removing the first "if" and see if it is faster.
+                //
+                if (fAttributeQName.uri != null && fAttributeQName.uri == uri) {
+                    // checkDuplicates(fAttributeQName, fAttributes);
+                    continue;
+                }
+                if (aprefix != XMLSymbols.EMPTY_STRING) {
+                    fAttributeQName.uri = uri;
+                    if (uri == null) {
+                        fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
+                                "AttributePrefixUnbound",
+                                new Object[]{fElementQName.rawname,fAttributeQName.rawname,aprefix},
+                                XMLErrorReporter.SEVERITY_FATAL_ERROR);
+                    }
+                    fAttributes.setURI(i, uri);
+                    // checkDuplicates(fAttributeQName, fAttributes);
+                }
+            }
+
+            if (length > 1) {
+                QName name = fAttributes.checkDuplicatesNS();
+                if (name != null) {
+                    if (name.uri != null) {
+                        fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
+                                "AttributeNSNotUnique",
+                                new Object[]{fElementQName.rawname, name.localpart, name.uri},
+                                XMLErrorReporter.SEVERITY_FATAL_ERROR);
+                    } else {
+                        fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
+                                "AttributeNotUnique",
+                                new Object[]{fElementQName.rawname, name.rawname},
+                                XMLErrorReporter.SEVERITY_FATAL_ERROR);
+                    }
+                }
+            }
+        }
+
+
+        if (fEmptyElement) {
+            //decrease the markup depth..
+            fMarkupDepth--;
+
+            // check that this element was opened in the same entity
+            if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
+                reportFatalError("ElementEntityMismatch",
+                        new Object[]{fCurrentElement.rawname});
+            }
+            // call handler
+            if (fDocumentHandler != null) {
+                if(DEBUG)
+                    System.out.println("emptyElement = " + fElementQName);
+
+                fDocumentHandler.emptyElement(fElementQName, fAttributes, null);
+            }
+
+            //We should not be popping out the context here in endELement becaause the namespace context is still
+            //valid when parser is at the endElement state.
+            fScanEndElement = true;
+            //if (fBindNamespaces) {
+            //  fNamespaceContext.popContext();
+            //}
+
+            //pop the element off the stack..
+            fElementStack.popElement();
+
+        } else {
+
+            if(dtdGrammarUtil != null)
+                dtdGrammarUtil.startElement(fElementQName,fAttributes);
+            if(fDocumentHandler != null){
+                //complete element and attributes are traversed in this function so we can send a callback
+                //here.
+                //<strong>we shouldn't be sending callback in scanDocument()</strong>
+                if(DEBUG)
+                    System.out.println("startElement = " + fElementQName);
+                fDocumentHandler.startElement(fElementQName, fAttributes, null);
+            }
+        }
+
+
+        if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +"<<< scanStartElement(): "+fEmptyElement);
+        return fEmptyElement;
+
+    } // scanStartElement():boolean
+
+
+
+    /**
+     * Scans an attribute.
+     * <p>
+     * <pre>
+     * [41] Attribute ::= Name Eq AttValue
+     * </pre>
+     * <p>
+     * <strong>Note:</strong> This method assumes that the next
+     * character on the stream is the first character of the attribute
+     * name.
+     * <p>
+     * <strong>Note:</strong> This method uses the fAttributeQName and
+     * fQName variables. The contents of these variables will be
+     * destroyed.
+     *
+     * @param attributes The attributes list for the scanned attribute.
+     */
+    protected void scanAttribute(XMLAttributesImpl attributes)
+    throws IOException, XNIException {
+        if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +">>> scanAttribute()");
+
+        // name
+        fEntityScanner.scanQName(fAttributeQName);
+
+        // equals
+        fEntityScanner.skipSpaces();
+        if (!fEntityScanner.skipChar('=')) {
+            reportFatalError("EqRequiredInAttribute",
+                    new Object[]{fCurrentElement.rawname,fAttributeQName.rawname});
+        }
+        fEntityScanner.skipSpaces();
+
+        // content
+        int attrIndex = 0 ;
+
+
+        //REVISIT: one more case needs to be included: external PE and standalone is no
+        boolean isVC =  fHasExternalDTD && !fStandalone;
+
+        // REVISIT: it seems that this function should not take attributes, and length
+        //fTempString would store attribute value
+        ///fTempString2 would store attribute non-normalized value
+
+        //this function doesn't use 'attIndex'. We are adding the attribute later
+        //after we have figured out that current attribute is not namespace declaration
+        //since scanAttributeValue doesn't use attIndex parameter therefore we
+        //can safely add the attribute later..
+        XMLString tmpStr = getString();
+        scanAttributeValue(tmpStr, fTempString2,
+                fAttributeQName.rawname, attributes,
+                attrIndex, isVC);
+
+        String value = null;
+        //fTempString.toString();
+
+        // record namespace declarations if any.
+        if (fBindNamespaces) {
+
+            String localpart = fAttributeQName.localpart;
+            String prefix = fAttributeQName.prefix != null
+                    ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
+            // when it's of form xmlns="..." or xmlns:prefix="...",
+            // it's a namespace declaration. but prefix:xmlns="..." isn't.
+            if (prefix == XMLSymbols.PREFIX_XMLNS ||
+                    prefix == XMLSymbols.EMPTY_STRING && localpart == XMLSymbols.PREFIX_XMLNS) {
+
+                // get the internalized value of this attribute
+                String uri = fSymbolTable.addSymbol(tmpStr.ch,tmpStr.offset,tmpStr.length);
+                value = uri;
+                // 1. "xmlns" can't be bound to any namespace
+                if (prefix == XMLSymbols.PREFIX_XMLNS && localpart == XMLSymbols.PREFIX_XMLNS) {
+                    fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
+                            "CantBindXMLNS",
+                            new Object[]{fAttributeQName},
+                            XMLErrorReporter.SEVERITY_FATAL_ERROR);
+                }
+
+                // 2. the namespace for "xmlns" can't be bound to any prefix
+                if (uri == NamespaceContext.XMLNS_URI) {
+                    fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
+                            "CantBindXMLNS",
+                            new Object[]{fAttributeQName},
+                            XMLErrorReporter.SEVERITY_FATAL_ERROR);
+                }
+
+                // 3. "xml" can't be bound to any other namespace than it's own
+                if (localpart == XMLSymbols.PREFIX_XML) {
+                    if (uri != NamespaceContext.XML_URI) {
+                        fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
+                                "CantBindXML",
+                                new Object[]{fAttributeQName},
+                                XMLErrorReporter.SEVERITY_FATAL_ERROR);
+                    }
+                }
+                // 4. the namespace for "xml" can't be bound to any other prefix
+                else {
+                    if (uri ==NamespaceContext.XML_URI) {
+                        fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
+                                "CantBindXML",
+                                new Object[]{fAttributeQName},
+                                XMLErrorReporter.SEVERITY_FATAL_ERROR);
+                    }
+                }
+                prefix = localpart != XMLSymbols.PREFIX_XMLNS ? localpart : XMLSymbols.EMPTY_STRING;
+                //set it equal to XMLSymbols.PREFIX_XMLNS when namespace declaration
+                // is of type xmlns = "..", in this case prefix = "" and localname = XMLSymbols.PREFIX_XMLNS
+                //this special behavior is because of dependency on this behavior in DOM components
+                if(prefix == XMLSymbols.EMPTY_STRING && localpart == XMLSymbols.PREFIX_XMLNS){
+                    fAttributeQName.prefix = XMLSymbols.PREFIX_XMLNS;
+                }
+                // http://www.w3.org/TR/1999/REC-xml-names-19990114/#dt-prefix
+                // We should only report an error if there is a prefix,
+                // that is, the local part is not "xmlns". -SG
+                if (uri == XMLSymbols.EMPTY_STRING && localpart != XMLSymbols.PREFIX_XMLNS) {
+                    fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
+                            "EmptyPrefixedAttName",
+                            new Object[]{fAttributeQName},
+                            XMLErrorReporter.SEVERITY_FATAL_ERROR);
+                }
+
+                // check for duplicate prefix bindings
+                if (((com.sun.org.apache.xerces.internal.util.NamespaceSupport) fNamespaceContext).containsPrefixInCurrentContext(prefix)) {
+                    reportFatalError("AttributeNotUnique",
+                            new Object[]{fCurrentElement.rawname,
+                            fAttributeQName.rawname});
+                }
+
+                // declare prefix in context
+                boolean declared = fNamespaceContext.declarePrefix(prefix, uri.length() != 0 ? uri : null);
+
+                // check for duplicate xmlns declarations
+                if (!declared) { // by convention, prefix == "xmlns" | "xml"
+                    // error if duplicate declaration
+                    if (fXmlnsDeclared) {
+                        reportFatalError("AttributeNotUnique",
+                                new Object[]{fCurrentElement.rawname,
+                                fAttributeQName.rawname});
+                    }
+
+                    // xmlns declared
+                    fXmlnsDeclared = true;
+                }
+
+                //xerces internals (XSAttributeChecker) has dependency on namespace declaration returned
+                //as part of XMLAttributes.
+                //addition of namespace declaration to the attribute list is controlled by fNotAddNSDeclAsAttribute
+                //feature. This is required in Stax where namespace declarations are not considered as attribute
+
+                if(fNotAddNSDeclAsAttribute){
+                    return ;
+                }
+            }
+        }
+
+        //add the attributes to the list of attributes
+        if (fBindNamespaces) {
+            attrIndex = attributes.getLength();
+            attributes.addAttributeNS(fAttributeQName, XMLSymbols.fCDATASymbol, null);
+        } else {
+            int oldLen = attributes.getLength();
+            attrIndex = attributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, null);
+
+            // WFC: Unique Att Spec
+            if (oldLen == attributes.getLength()) {
+                reportFatalError("AttributeNotUnique",
+                        new Object[]{fCurrentElement.rawname,
+                                fAttributeQName.rawname});
+            }
+        }
+
+        attributes.setValue(attrIndex, value,tmpStr);
+        //attributes.setNonNormalizedValue(attrIndex, fTempString2.toString());
+        //removing  as we are not using non-normalized values . -Venu
+        attributes.setSpecified(attrIndex, true);
+
+        // attempt to bind attribute
+        if (fAttributeQName.prefix != null) {
+            attributes.setURI(attrIndex, fNamespaceContext.getURI(fAttributeQName.prefix));
+        }
+
+        if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +"<<< scanAttribute()");
+    } // scanAttribute(XMLAttributes)
+
+
+
+
+
+    /** Creates a content driver. */
+    protected Driver createContentDriver() {
+        return new NSContentDriver();
+    } // createContentDriver():Driver
+
+    /**
+     * Driver to handle content scanning.
+     */
+    protected final class NSContentDriver
+            extends ContentDriver {
+        /**
+         * Scan for root element hook. This method is a hook for
+         * subclasses to add code that handles scanning for the root
+         * element. This method will also attempt to remove DTD validator
+         * from the pipeline, if there is no DTD grammar. If DTD validator
+         * is no longer in the pipeline bind namespaces in the scanner.
+         *
+         *
+         * @return True if the caller should stop and return true which
+         *          allows the scanner to switch to a new scanning
+         *          driver. A return value of false indicates that
+         *          the content driver should continue as normal.
+         */
+        protected boolean scanRootElementHook()
+        throws IOException, XNIException {
+
+            reconfigurePipeline();
+            if (scanStartElement()) {
+                setScannerState(SCANNER_STATE_TRAILING_MISC);
+                setDriver(fTrailingMiscDriver);
+                return true;
+            }
+            return false;
+
+        } // scanRootElementHook():boolean
+
+        /**
+         * Re-configures pipeline by removing the DTD validator
+         * if no DTD grammar exists. If no validator exists in the
+         * pipeline or there is no DTD grammar, namespace binding
+         * is performed by the scanner in the enclosing class.
+         */
+        private void reconfigurePipeline() {
+            //fDTDValidator will be null in Stax mode
+            if (fNamespaces && fDTDValidator == null) {
+                fBindNamespaces = true;
+            }
+            else if (fNamespaces && !fDTDValidator.hasGrammar() ) {
+                fBindNamespaces = true;
+                fPerformValidation = fDTDValidator.validate();
+                // re-configure pipeline by removing DTDValidator
+                XMLDocumentSource source = fDTDValidator.getDocumentSource();
+                XMLDocumentHandler handler = fDTDValidator.getDocumentHandler();
+                source.setDocumentHandler(handler);
+                if (handler != null)
+                    handler.setDocumentSource(source);
+                fDTDValidator.setDocumentSource(null);
+                fDTDValidator.setDocumentHandler(null);
+            }
+        } // reconfigurePipeline()
+    }
+
+} // class XMLNSDocumentScannerImpl