1 /*
   2  * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 
   5 /*
   6  * Copyright 2005 The Apache Software Foundation.
   7  *
   8  * Licensed under the Apache License, Version 2.0 (the "License");
   9  * you may not use this file except in compliance with the License.
  10  * You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 
  21 package com.sun.org.apache.xerces.internal.impl;
  22 
  23 import java.io.IOException;
  24 import com.sun.org.apache.xerces.internal.xni.XMLString;
  25 import com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidatorFilter;
  26 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
  27 import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
  28 import com.sun.org.apache.xerces.internal.util.XMLAttributesIteratorImpl;
  29 import com.sun.org.apache.xerces.internal.util.XMLStringBuffer;
  30 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
  31 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  32 import com.sun.org.apache.xerces.internal.xni.QName;
  33 import com.sun.org.apache.xerces.internal.xni.XNIException;
  34 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
  35 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  36 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
  37 import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
  38 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
  39 import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
  40 
  41 import javax.xml.stream.XMLInputFactory;
  42 import javax.xml.stream.XMLStreamConstants;
  43 import javax.xml.stream.events.XMLEvent;
  44 
  45 /**
  46  * This class adds the functionality of namespace processing.
  47  *
  48  * This class has been modified as per the new design which is more suited to
  49  * efficiently build pull parser. Lot of improvements have been done and
  50  * the code has been added to support stax functionality/features.
  51  *
  52  *
  53  * This class scans an XML document, checks if document has a DTD, and if
  54  * DTD is not found the scanner will remove the DTD Validator from the pipeline and perform
  55  * namespace binding.
  56  *
  57  *
  58  * @author Neeraj Bajaj, Sun Microsystems
  59  * @author Venugopal Rao K, Sun Microsystems
  60  * @author Elena Litani, IBM
  61  * @version $Id: XMLNSDocumentScannerImpl.java,v 1.11 2010-11-01 04:39:41 joehw Exp $
  62  */
  63 public class XMLNSDocumentScannerImpl
  64         extends XMLDocumentScannerImpl {
  65 
  66     /**
  67      * If is true, the dtd validator is no longer in the pipeline
  68      * and the scanner should bind namespaces
  69      */
  70     protected boolean fBindNamespaces;
  71 
  72     /** If validating parser, make sure we report an error in the
  73      *   scanner if DTD grammar is missing.*/
  74     protected boolean fPerformValidation;
  75 
  76 
  77     /** Default value of this feature is false, when in Stax mode this should be true */
  78     protected boolean fNotAddNSDeclAsAttribute = false;
  79 
  80     /** DTD validator */
  81      private XMLDTDValidatorFilter fDTDValidator;
  82 
  83      /** xmlns, default Namespace, declared */
  84      private boolean fXmlnsDeclared = false;
  85 
  86     /** Resets the fields of this scanner.
  87      */
  88     public void reset(PropertyManager propertyManager) {
  89         setPropertyManager(propertyManager);
  90         super.reset(propertyManager);
  91         fBindNamespaces = false;
  92         fNotAddNSDeclAsAttribute = !((Boolean)propertyManager.getProperty(Constants.ADD_NAMESPACE_DECL_AS_ATTRIBUTE)).booleanValue();
  93     }
  94 
  95     public void reset(XMLComponentManager componentManager)
  96     throws XMLConfigurationException {
  97         super.reset(componentManager);
  98         fNotAddNSDeclAsAttribute = false ;
  99         fPerformValidation = false;
 100         fBindNamespaces = false;
 101     }
 102 
 103     /** return the next state on the input
 104      *
 105      * @return int
 106      */
 107 
 108     public int next() throws IOException, XNIException {
 109         //since namespace context should still be valid when the parser is at the end element state therefore
 110         //we pop the context only when next() has been called after the end element state was encountered. - nb.
 111 
 112         if((fScannerLastState == XMLEvent.END_ELEMENT) && fBindNamespaces){
 113             fScannerLastState = -1;
 114             fNamespaceContext.popContext();
 115         }
 116 
 117         return fScannerLastState = super.next();
 118     }
 119 
 120     /**
 121      * The scanner is responsible for removing DTD validator
 122      * from the pipeline if it is not needed.
 123      *
 124      * @param previous The filter component before DTDValidator
 125      * @param dtdValidator
 126      *                 The DTDValidator
 127      * @param next     The documentHandler after the DTDValidator
 128      */
 129     public void setDTDValidator(XMLDTDValidatorFilter dtd){
 130         fDTDValidator = dtd;
 131     }
 132 
 133 
 134 
 135     /**
 136      * Scans a start element. This method will handle the binding of
 137      * namespace information and notifying the handler of the start
 138      * of the element.
 139      * <p>
 140      * <pre>
 141      * [44] EmptyElemTag ::= '&lt;' Name (S Attribute)* S? '/>'
 142      * [40] STag ::= '&lt;' Name (S Attribute)* S? '>'
 143      * </pre>
 144      * <p>
 145      * <strong>Note:</strong> This method assumes that the leading
 146      * '&lt;' character has been consumed.
 147      * <p>
 148      * <strong>Note:</strong> This method uses the fElementQName and
 149      * fAttributes variables. The contents of these variables will be
 150      * destroyed. The caller should copy important information out of
 151      * these variables before calling this method.
 152      *
 153      * @return True if element is empty. (i.e. It matches
 154      *          production [44].
 155      */
 156     protected boolean scanStartElement()
 157     throws IOException, XNIException {
 158 
 159         if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +">>> scanStartElement()");
 160         //when skipping is true and no more elements should be added
 161         if(fSkip && !fAdd){
 162             //get the stored element -- if everything goes right this should match the
 163             //token in the buffer
 164 
 165             QName name = fElementStack.getNext();
 166 
 167             if(DEBUG_SKIP_ALGORITHM){
 168                 System.out.println("Trying to skip String = " + name.rawname);
 169             }
 170 
 171             //Be conservative -- if skipping fails -- stop.
 172             fSkip = fEntityScanner.skipString(name.rawname); // skipQElement(name);
 173 
 174             if(fSkip){
 175                 if(DEBUG_SKIP_ALGORITHM){
 176                     System.out.println("Element SUCESSFULLY skipped = " + name.rawname);
 177                 }
 178                 fElementStack.push();
 179                 fElementQName = name;
 180             }else{
 181                 //if skipping fails reposition the stack or fallback to normal way of processing
 182                 fElementStack.reposition();
 183                 if(DEBUG_SKIP_ALGORITHM){
 184                     System.out.println("Element was NOT skipped, REPOSITIONING stack" );
 185                 }
 186             }
 187         }
 188 
 189         //we are still at the stage of adding elements
 190         //the elements were not matched or
 191         //fSkip is not set to true
 192         if(!fSkip || fAdd){
 193             //get the next element from the stack
 194             fElementQName = fElementStack.nextElement();
 195             // There are two variables,fNamespaces and fBindNamespaces
 196             //StAX uses XMLNSDocumentScannerImpl so this distinction needs to be maintained
 197             if (fNamespaces) {
 198                 fEntityScanner.scanQName(fElementQName);
 199             } else {
 200                 String name = fEntityScanner.scanName();
 201                 fElementQName.setValues(null, name, name, null);
 202             }
 203 
 204             if(DEBUG)System.out.println("Element scanned in start element is " + fElementQName.toString());
 205             if(DEBUG_SKIP_ALGORITHM){
 206                 if(fAdd){
 207                     System.out.println("Elements are being ADDED -- elemet added is = " + fElementQName.rawname + " at count = " + fElementStack.fCount);
 208                 }
 209             }
 210 
 211         }
 212 
 213         //when the elements are being added , we need to check if we are set for skipping the elements
 214         if(fAdd){
 215             //this sets the value of fAdd variable
 216             fElementStack.matchElement(fElementQName);
 217         }
 218 
 219         //xxx: We dont need another pointer, fCurrentElement, we can use fElementQName
 220         fCurrentElement = fElementQName;
 221 
 222         String rawname = fElementQName.rawname;
 223         if (fBindNamespaces) {
 224             fNamespaceContext.pushContext();
 225             if (fScannerState == SCANNER_STATE_ROOT_ELEMENT) {
 226                 if (fPerformValidation) {
 227                     fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 228                             "MSG_GRAMMAR_NOT_FOUND",
 229                             new Object[]{ rawname},
 230                             XMLErrorReporter.SEVERITY_ERROR);
 231 
 232                             if (fDoctypeName == null || !fDoctypeName.equals(rawname)) {
 233                                 fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,
 234                                         "RootElementTypeMustMatchDoctypedecl",
 235                                         new Object[]{fDoctypeName, rawname},
 236                                         XMLErrorReporter.SEVERITY_ERROR);
 237                             }
 238                 }
 239             }
 240         }
 241 
 242 
 243         fEmptyElement = false;
 244         fAttributes.removeAllAttributes();
 245 
 246         if(!seekCloseOfStartTag()){
 247             fReadingAttributes = true;
 248             fAttributeCacheUsedCount =0;
 249             fStringBufferIndex =0;
 250             fAddDefaultAttr = true;
 251             fXmlnsDeclared = false;
 252 
 253             do {
 254                 scanAttribute(fAttributes);
 255                 if (fSecurityManager != null && (!fSecurityManager.isNoLimit(fElementAttributeLimit)) &&
 256                         fAttributes.getLength() > fElementAttributeLimit){
 257                     fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 258                                                  "ElementAttributeLimit",
 259                                                  new Object[]{rawname, fElementAttributeLimit },
 260                                                  XMLErrorReporter.SEVERITY_FATAL_ERROR );
 261                 }
 262 
 263             } while (!seekCloseOfStartTag());
 264             fReadingAttributes=false;
 265         }
 266 
 267         if (fBindNamespaces) {
 268             // REVISIT: is it required? forbit xmlns prefix for element
 269             if (fElementQName.prefix == XMLSymbols.PREFIX_XMLNS) {
 270                 fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
 271                         "ElementXMLNSPrefix",
 272                         new Object[]{fElementQName.rawname},
 273                         XMLErrorReporter.SEVERITY_FATAL_ERROR);
 274             }
 275 
 276             // bind the element
 277             String prefix = fElementQName.prefix != null
 278                     ? fElementQName.prefix : XMLSymbols.EMPTY_STRING;
 279             // assign uri to the element
 280             fElementQName.uri = fNamespaceContext.getURI(prefix);
 281             // make sure that object in the element stack is updated as well
 282             fCurrentElement.uri = fElementQName.uri;
 283 
 284             if (fElementQName.prefix == null && fElementQName.uri != null) {
 285                 fElementQName.prefix = XMLSymbols.EMPTY_STRING;
 286             }
 287             if (fElementQName.prefix != null && fElementQName.uri == null) {
 288                 fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
 289                         "ElementPrefixUnbound",
 290                         new Object[]{fElementQName.prefix, fElementQName.rawname},
 291                         XMLErrorReporter.SEVERITY_FATAL_ERROR);
 292             }
 293 
 294             // bind attributes (xmlns are already bound bellow)
 295             int length = fAttributes.getLength();
 296             // fLength = 0; //initialize structure
 297             for (int i = 0; i < length; i++) {
 298                 fAttributes.getName(i, fAttributeQName);
 299 
 300                 String aprefix = fAttributeQName.prefix != null
 301                         ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
 302                 String uri = fNamespaceContext.getURI(aprefix);
 303                 // REVISIT: try removing the first "if" and see if it is faster.
 304                 //
 305                 if (fAttributeQName.uri != null && fAttributeQName.uri == uri) {
 306                     // checkDuplicates(fAttributeQName, fAttributes);
 307                     continue;
 308                 }
 309                 if (aprefix != XMLSymbols.EMPTY_STRING) {
 310                     fAttributeQName.uri = uri;
 311                     if (uri == null) {
 312                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
 313                                 "AttributePrefixUnbound",
 314                                 new Object[]{fElementQName.rawname,fAttributeQName.rawname,aprefix},
 315                                 XMLErrorReporter.SEVERITY_FATAL_ERROR);
 316                     }
 317                     fAttributes.setURI(i, uri);
 318                     // checkDuplicates(fAttributeQName, fAttributes);
 319                 }
 320             }
 321 
 322             if (length > 1) {
 323                 QName name = fAttributes.checkDuplicatesNS();
 324                 if (name != null) {
 325                     if (name.uri != null) {
 326                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
 327                                 "AttributeNSNotUnique",
 328                                 new Object[]{fElementQName.rawname, name.localpart, name.uri},
 329                                 XMLErrorReporter.SEVERITY_FATAL_ERROR);
 330                     } else {
 331                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
 332                                 "AttributeNotUnique",
 333                                 new Object[]{fElementQName.rawname, name.rawname},
 334                                 XMLErrorReporter.SEVERITY_FATAL_ERROR);
 335                     }
 336                 }
 337             }
 338         }
 339 
 340 
 341         if (fEmptyElement) {
 342             //decrease the markup depth..
 343             fMarkupDepth--;
 344 
 345             // check that this element was opened in the same entity
 346             if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
 347                 reportFatalError("ElementEntityMismatch",
 348                         new Object[]{fCurrentElement.rawname});
 349             }
 350             // call handler
 351             if (fDocumentHandler != null) {
 352                 if(DEBUG)
 353                     System.out.println("emptyElement = " + fElementQName);
 354 
 355                 fDocumentHandler.emptyElement(fElementQName, fAttributes, null);
 356             }
 357 
 358             //We should not be popping out the context here in endELement becaause the namespace context is still
 359             //valid when parser is at the endElement state.
 360             fScanEndElement = true;
 361             //if (fBindNamespaces) {
 362             //  fNamespaceContext.popContext();
 363             //}
 364 
 365             //pop the element off the stack..
 366             fElementStack.popElement();
 367 
 368         } else {
 369 
 370             if(dtdGrammarUtil != null)
 371                 dtdGrammarUtil.startElement(fElementQName,fAttributes);
 372             if(fDocumentHandler != null){
 373                 //complete element and attributes are traversed in this function so we can send a callback
 374                 //here.
 375                 //<strong>we shouldn't be sending callback in scanDocument()</strong>
 376                 if(DEBUG)
 377                     System.out.println("startElement = " + fElementQName);
 378                 fDocumentHandler.startElement(fElementQName, fAttributes, null);
 379             }
 380         }
 381 
 382 
 383         if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +"<<< scanStartElement(): "+fEmptyElement);
 384         return fEmptyElement;
 385 
 386     } // scanStartElement():boolean
 387 
 388 
 389 
 390     /**
 391      * Scans an attribute.
 392      * <p>
 393      * <pre>
 394      * [41] Attribute ::= Name Eq AttValue
 395      * </pre>
 396      * <p>
 397      * <strong>Note:</strong> This method assumes that the next
 398      * character on the stream is the first character of the attribute
 399      * name.
 400      * <p>
 401      * <strong>Note:</strong> This method uses the fAttributeQName and
 402      * fQName variables. The contents of these variables will be
 403      * destroyed.
 404      *
 405      * @param attributes The attributes list for the scanned attribute.
 406      */
 407     protected void scanAttribute(XMLAttributesImpl attributes)
 408     throws IOException, XNIException {
 409         if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +">>> scanAttribute()");
 410 
 411         // name
 412         fEntityScanner.scanQName(fAttributeQName);
 413 
 414         // equals
 415         fEntityScanner.skipSpaces();
 416         if (!fEntityScanner.skipChar('=')) {
 417             reportFatalError("EqRequiredInAttribute",
 418                     new Object[]{fCurrentElement.rawname,fAttributeQName.rawname});
 419         }
 420         fEntityScanner.skipSpaces();
 421 
 422         // content
 423         int attrIndex = 0 ;
 424 
 425 
 426         //REVISIT: one more case needs to be included: external PE and standalone is no
 427         boolean isVC =  fHasExternalDTD && !fStandalone;
 428 
 429         // REVISIT: it seems that this function should not take attributes, and length
 430         //fTempString would store attribute value
 431         ///fTempString2 would store attribute non-normalized value
 432 
 433         //this function doesn't use 'attIndex'. We are adding the attribute later
 434         //after we have figured out that current attribute is not namespace declaration
 435         //since scanAttributeValue doesn't use attIndex parameter therefore we
 436         //can safely add the attribute later..
 437         XMLString tmpStr = getString();
 438         scanAttributeValue(tmpStr, fTempString2,
 439                 fAttributeQName.rawname, attributes,
 440                 attrIndex, isVC);
 441 
 442         String value = null;
 443         //fTempString.toString();
 444 
 445         // record namespace declarations if any.
 446         if (fBindNamespaces) {
 447 
 448             String localpart = fAttributeQName.localpart;
 449             String prefix = fAttributeQName.prefix != null
 450                     ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
 451             // when it's of form xmlns="..." or xmlns:prefix="...",
 452             // it's a namespace declaration. but prefix:xmlns="..." isn't.
 453             if (prefix == XMLSymbols.PREFIX_XMLNS ||
 454                     prefix == XMLSymbols.EMPTY_STRING && localpart == XMLSymbols.PREFIX_XMLNS) {
 455 
 456                 // get the internalized value of this attribute
 457                 String uri = fSymbolTable.addSymbol(tmpStr.ch,tmpStr.offset,tmpStr.length);
 458                 value = uri;
 459                 // 1. "xmlns" can't be bound to any namespace
 460                 if (prefix == XMLSymbols.PREFIX_XMLNS && localpart == XMLSymbols.PREFIX_XMLNS) {
 461                     fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
 462                             "CantBindXMLNS",
 463                             new Object[]{fAttributeQName},
 464                             XMLErrorReporter.SEVERITY_FATAL_ERROR);
 465                 }
 466 
 467                 // 2. the namespace for "xmlns" can't be bound to any prefix
 468                 if (uri == NamespaceContext.XMLNS_URI) {
 469                     fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
 470                             "CantBindXMLNS",
 471                             new Object[]{fAttributeQName},
 472                             XMLErrorReporter.SEVERITY_FATAL_ERROR);
 473                 }
 474 
 475                 // 3. "xml" can't be bound to any other namespace than it's own
 476                 if (localpart == XMLSymbols.PREFIX_XML) {
 477                     if (uri != NamespaceContext.XML_URI) {
 478                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
 479                                 "CantBindXML",
 480                                 new Object[]{fAttributeQName},
 481                                 XMLErrorReporter.SEVERITY_FATAL_ERROR);
 482                     }
 483                 }
 484                 // 4. the namespace for "xml" can't be bound to any other prefix
 485                 else {
 486                     if (uri ==NamespaceContext.XML_URI) {
 487                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
 488                                 "CantBindXML",
 489                                 new Object[]{fAttributeQName},
 490                                 XMLErrorReporter.SEVERITY_FATAL_ERROR);
 491                     }
 492                 }
 493                 prefix = localpart != XMLSymbols.PREFIX_XMLNS ? localpart : XMLSymbols.EMPTY_STRING;
 494                 //set it equal to XMLSymbols.PREFIX_XMLNS when namespace declaration
 495                 // is of type xmlns = "..", in this case prefix = "" and localname = XMLSymbols.PREFIX_XMLNS
 496                 //this special behavior is because of dependency on this behavior in DOM components
 497                 if(prefix == XMLSymbols.EMPTY_STRING && localpart == XMLSymbols.PREFIX_XMLNS){
 498                     fAttributeQName.prefix = XMLSymbols.PREFIX_XMLNS;
 499                 }
 500                 // http://www.w3.org/TR/1999/REC-xml-names-19990114/#dt-prefix
 501                 // We should only report an error if there is a prefix,
 502                 // that is, the local part is not "xmlns". -SG
 503                 if (uri == XMLSymbols.EMPTY_STRING && localpart != XMLSymbols.PREFIX_XMLNS) {
 504                     fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
 505                             "EmptyPrefixedAttName",
 506                             new Object[]{fAttributeQName},
 507                             XMLErrorReporter.SEVERITY_FATAL_ERROR);
 508                 }
 509 
 510                 // check for duplicate prefix bindings
 511                 if (((com.sun.org.apache.xerces.internal.util.NamespaceSupport) fNamespaceContext).containsPrefixInCurrentContext(prefix)) {
 512                     reportFatalError("AttributeNotUnique",
 513                             new Object[]{fCurrentElement.rawname,
 514                             fAttributeQName.rawname});
 515                 }
 516 
 517                 // declare prefix in context
 518                 boolean declared = fNamespaceContext.declarePrefix(prefix, uri.length() != 0 ? uri : null);
 519 
 520                 // check for duplicate xmlns declarations
 521                 if (!declared) { // by convention, prefix == "xmlns" | "xml"
 522                     // error if duplicate declaration
 523                     if (fXmlnsDeclared) {
 524                         reportFatalError("AttributeNotUnique",
 525                                 new Object[]{fCurrentElement.rawname,
 526                                 fAttributeQName.rawname});
 527                     }
 528 
 529                     // xmlns declared
 530                     fXmlnsDeclared = true;
 531                 }
 532 
 533                 //xerces internals (XSAttributeChecker) has dependency on namespace declaration returned
 534                 //as part of XMLAttributes.
 535                 //addition of namespace declaration to the attribute list is controlled by fNotAddNSDeclAsAttribute
 536                 //feature. This is required in Stax where namespace declarations are not considered as attribute
 537 
 538                 if(fNotAddNSDeclAsAttribute){
 539                     return ;
 540                 }
 541             }
 542         }
 543 
 544         //add the attributes to the list of attributes
 545         if (fBindNamespaces) {
 546             attrIndex = attributes.getLength();
 547             attributes.addAttributeNS(fAttributeQName, XMLSymbols.fCDATASymbol, null);
 548         } else {
 549             int oldLen = attributes.getLength();
 550             attrIndex = attributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, null);
 551 
 552             // WFC: Unique Att Spec
 553             if (oldLen == attributes.getLength()) {
 554                 reportFatalError("AttributeNotUnique",
 555                         new Object[]{fCurrentElement.rawname,
 556                                 fAttributeQName.rawname});
 557             }
 558         }
 559 
 560         attributes.setValue(attrIndex, value,tmpStr);
 561         //attributes.setNonNormalizedValue(attrIndex, fTempString2.toString());
 562         //removing  as we are not using non-normalized values . -Venu
 563         attributes.setSpecified(attrIndex, true);
 564 
 565         // attempt to bind attribute
 566         if (fAttributeQName.prefix != null) {
 567             attributes.setURI(attrIndex, fNamespaceContext.getURI(fAttributeQName.prefix));
 568         }
 569 
 570         if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +"<<< scanAttribute()");
 571     } // scanAttribute(XMLAttributes)
 572 
 573 
 574 
 575 
 576 
 577     /** Creates a content driver. */
 578     protected Driver createContentDriver() {
 579         return new NSContentDriver();
 580     } // createContentDriver():Driver
 581 
 582     /**
 583      * Driver to handle content scanning.
 584      */
 585     protected final class NSContentDriver
 586             extends ContentDriver {
 587         /**
 588          * Scan for root element hook. This method is a hook for
 589          * subclasses to add code that handles scanning for the root
 590          * element. This method will also attempt to remove DTD validator
 591          * from the pipeline, if there is no DTD grammar. If DTD validator
 592          * is no longer in the pipeline bind namespaces in the scanner.
 593          *
 594          *
 595          * @return True if the caller should stop and return true which
 596          *          allows the scanner to switch to a new scanning
 597          *          driver. A return value of false indicates that
 598          *          the content driver should continue as normal.
 599          */
 600         protected boolean scanRootElementHook()
 601         throws IOException, XNIException {
 602 
 603             reconfigurePipeline();
 604             if (scanStartElement()) {
 605                 setScannerState(SCANNER_STATE_TRAILING_MISC);
 606                 setDriver(fTrailingMiscDriver);
 607                 return true;
 608             }
 609             return false;
 610 
 611         } // scanRootElementHook():boolean
 612 
 613         /**
 614          * Re-configures pipeline by removing the DTD validator
 615          * if no DTD grammar exists. If no validator exists in the
 616          * pipeline or there is no DTD grammar, namespace binding
 617          * is performed by the scanner in the enclosing class.
 618          */
 619         private void reconfigurePipeline() {
 620             //fDTDValidator will be null in Stax mode
 621             if (fNamespaces && fDTDValidator == null) {
 622                 fBindNamespaces = true;
 623             }
 624             else if (fNamespaces && !fDTDValidator.hasGrammar() ) {
 625                 fBindNamespaces = true;
 626                 fPerformValidation = fDTDValidator.validate();
 627                 // re-configure pipeline by removing DTDValidator
 628                 XMLDocumentSource source = fDTDValidator.getDocumentSource();
 629                 XMLDocumentHandler handler = fDTDValidator.getDocumentHandler();
 630                 source.setDocumentHandler(handler);
 631                 if (handler != null)
 632                     handler.setDocumentSource(source);
 633                 fDTDValidator.setDocumentSource(null);
 634                 fDTDValidator.setDocumentHandler(null);
 635             }
 636         } // reconfigurePipeline()
 637     }
 638 
 639 } // class XMLNSDocumentScannerImpl