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