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