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 ::= '<' Name (S Attribute)* S? '/>' 137 * [40] STag ::= '<' Name (S Attribute)* S? '>' 138 * </pre> 139 * <p> 140 * <strong>Note:</strong> This method assumes that the leading 141 * '<' 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