1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * The Apache Software License, Version 1.1 7 * 8 * 9 * Copyright (c) 2000-2002 The Apache Software Foundation. All rights 10 * reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in 21 * the documentation and/or other materials provided with the 22 * distribution. 23 * 24 * 3. The end-user documentation included with the redistribution, 25 * if any, must include the following acknowledgment: 26 * "This product includes software developed by the 27 * Apache Software Foundation (http://www.apache.org/)." 28 * Alternately, this acknowledgment may appear in the software itself, 29 * if and wherever such third-party acknowledgments normally appear. 30 * 31 * 4. The names "Xerces" and "Apache Software Foundation" must 32 * not be used to endorse or promote products derived from this 33 * software without prior written permission. For written 34 * permission, please contact apache@apache.org. 35 * 36 * 5. Products derived from this software may not be called "Apache", 37 * nor may "Apache" appear in their name, without prior written 38 * permission of the Apache Software Foundation. 39 * 40 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 41 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 42 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 43 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 46 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 47 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 48 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 49 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 50 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * ==================================================================== 53 * 54 * This software consists of voluntary contributions made by many 55 * individuals on behalf of the Apache Software Foundation and was 56 * originally based on software copyright (c) 1999, International 57 * Business Machines, Inc., http://www.apache.org. For more 58 * information on the Apache Software Foundation, please see 59 * <http://www.apache.org/>. 60 */ 61 62 package com.sun.org.apache.xerces.internal.impl; 63 64 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter; 65 import com.sun.org.apache.xerces.internal.util.SymbolTable; 66 import com.sun.org.apache.xerces.internal.util.XMLSymbols; 67 import com.sun.org.apache.xerces.internal.xni.Augmentations; 68 import com.sun.org.apache.xerces.internal.xni.NamespaceContext; 69 import com.sun.org.apache.xerces.internal.xni.QName; 70 import com.sun.org.apache.xerces.internal.xni.XMLAttributes; 71 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler; 72 import com.sun.org.apache.xerces.internal.xni.XMLLocator; 73 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier; 74 import com.sun.org.apache.xerces.internal.xni.XMLString; 75 import com.sun.org.apache.xerces.internal.xni.XNIException; 76 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent; 77 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager; 78 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException; 79 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentFilter; 80 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource; 81 82 /** 83 * This class performs namespace binding on the startElement and endElement 84 * method calls and passes all other methods through to the registered 85 * document handler. This class can be configured to only pass the 86 * start and end prefix mappings (start/endPrefixMapping). 87 * <p> 88 * This component requires the following features and properties from the 89 * component manager that uses it: 90 * <ul> 91 * <li>http://xml.org/sax/features/namespaces</li> 92 * <li>http://apache.org/xml/properties/internal/symbol-table</li> 93 * <li>http://apache.org/xml/properties/internal/error-reporter</li> 94 * </ul> 95 * 96 * @xerces.internal 97 * 98 * @author Andy Clark, IBM 99 * 100 * @version $Id: XMLNamespaceBinder.java,v 1.4 2010-11-01 04:39:41 joehw Exp $ 101 */ 102 public class XMLNamespaceBinder 103 implements XMLComponent, XMLDocumentFilter { 104 105 // 106 // Constants 107 // 108 109 // feature identifiers 110 111 /** Feature identifier: namespaces. */ 112 protected static final String NAMESPACES = 113 Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; 114 115 // property identifiers 116 117 /** Property identifier: symbol table. */ 118 protected static final String SYMBOL_TABLE = 119 Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; 120 121 /** Property identifier: error reporter. */ 122 protected static final String ERROR_REPORTER = 123 Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; 124 125 // recognized features and properties 126 127 /** Recognized features. */ 128 private static final String[] RECOGNIZED_FEATURES = { 129 NAMESPACES, 130 }; 131 132 /** Feature defaults. */ 133 private static final Boolean[] FEATURE_DEFAULTS = { 134 null, 135 }; 136 137 /** Recognized properties. */ 138 private static final String[] RECOGNIZED_PROPERTIES = { 139 SYMBOL_TABLE, 140 ERROR_REPORTER, 141 }; 142 143 /** Property defaults. */ 144 private static final Object[] PROPERTY_DEFAULTS = { 145 null, 146 null, 147 }; 148 149 // 150 // Data 151 // 152 153 // features 154 155 /** Namespaces. */ 156 protected boolean fNamespaces; 157 158 // properties 159 160 /** Symbol table. */ 161 protected SymbolTable fSymbolTable; 162 163 /** Error reporter. */ 164 protected XMLErrorReporter fErrorReporter; 165 166 // handlers 167 168 /** Document handler. */ 169 protected XMLDocumentHandler fDocumentHandler; 170 171 protected XMLDocumentSource fDocumentSource; 172 173 // settings 174 175 /** Only pass start and end prefix mapping events. */ 176 protected boolean fOnlyPassPrefixMappingEvents; 177 178 // shared context 179 180 /** Namespace context. */ 181 private NamespaceContext fNamespaceContext; 182 183 // temp vars 184 185 /** Attribute QName. */ 186 private QName fAttributeQName = new QName(); 187 188 // 189 // Constructors 190 // 191 192 /** Default constructor. */ 193 public XMLNamespaceBinder() { 194 } // <init>() 195 196 // 197 // Public methods 198 // 199 200 // settings 201 202 /** 203 * Sets whether the namespace binder only passes the prefix mapping 204 * events to the registered document handler or passes all document 205 * events. 206 * 207 * @param onlyPassPrefixMappingEvents True to pass only the prefix 208 * mapping events; false to pass 209 * all events. 210 */ 211 public void setOnlyPassPrefixMappingEvents(boolean onlyPassPrefixMappingEvents) { 212 fOnlyPassPrefixMappingEvents = onlyPassPrefixMappingEvents; 213 } // setOnlyPassPrefixMappingEvents(boolean) 214 215 /** 216 * Returns true if the namespace binder only passes the prefix mapping 217 * events to the registered document handler; false if the namespace 218 * binder passes all document events. 219 */ 220 public boolean getOnlyPassPrefixMappingEvents() { 221 return fOnlyPassPrefixMappingEvents; 222 } // getOnlyPassPrefixMappingEvents():boolean 223 224 // 225 // XMLComponent methods 226 // 227 228 /** 229 * Resets the component. The component can query the component manager 230 * about any features and properties that affect the operation of the 231 * component. 232 * 233 * @param componentManager The component manager. 234 * 235 * @throws SAXException Thrown by component on initialization error. 236 * For example, if a feature or property is 237 * required for the operation of the component, the 238 * component manager may throw a 239 * SAXNotRecognizedException or a 240 * SAXNotSupportedException. 241 */ 242 public void reset(XMLComponentManager componentManager) 243 throws XNIException { 244 245 // features 246 fNamespaces = componentManager.getFeature(NAMESPACES, true); 247 248 // Xerces properties 249 fSymbolTable = (SymbolTable)componentManager.getProperty(SYMBOL_TABLE); 250 fErrorReporter = (XMLErrorReporter)componentManager.getProperty(ERROR_REPORTER); 251 252 } // reset(XMLComponentManager) 253 254 /** 255 * Returns a list of feature identifiers that are recognized by 256 * this component. This method may return null if no features 257 * are recognized by this component. 258 */ 259 public String[] getRecognizedFeatures() { 260 return (String[])(RECOGNIZED_FEATURES.clone()); 261 } // getRecognizedFeatures():String[] 262 263 /** 264 * Sets the state of a feature. This method is called by the component 265 * manager any time after reset when a feature changes state. 266 * <p> 267 * <strong>Note:</strong> Components should silently ignore features 268 * that do not affect the operation of the component. 269 * 270 * @param featureId The feature identifier. 271 * @param state The state of the feature. 272 * 273 * @throws SAXNotRecognizedException The component should not throw 274 * this exception. 275 * @throws SAXNotSupportedException The component should not throw 276 * this exception. 277 */ 278 public void setFeature(String featureId, boolean state) 279 throws XMLConfigurationException { 280 } // setFeature(String,boolean) 281 282 /** 283 * Returns a list of property identifiers that are recognized by 284 * this component. This method may return null if no properties 285 * are recognized by this component. 286 */ 287 public String[] getRecognizedProperties() { 288 return (String[])(RECOGNIZED_PROPERTIES.clone()); 289 } // getRecognizedProperties():String[] 290 291 /** 292 * Sets the value of a property during parsing. 293 * 294 * @param propertyId 295 * @param value 296 */ 297 public void setProperty(String propertyId, Object value) 298 throws XMLConfigurationException { 299 300 // Xerces properties 301 if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) { 302 final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length(); 303 304 if (suffixLength == Constants.SYMBOL_TABLE_PROPERTY.length() && 305 propertyId.endsWith(Constants.SYMBOL_TABLE_PROPERTY)) { 306 fSymbolTable = (SymbolTable)value; 307 } 308 else if (suffixLength == Constants.ERROR_REPORTER_PROPERTY.length() && 309 propertyId.endsWith(Constants.ERROR_REPORTER_PROPERTY)) { 310 fErrorReporter = (XMLErrorReporter)value; 311 } 312 return; 313 } 314 315 } // setProperty(String,Object) 316 317 /** 318 * Returns the default state for a feature, or null if this 319 * component does not want to report a default value for this 320 * feature. 321 * 322 * @param featureId The feature identifier. 323 * 324 * @since Xerces 2.2.0 325 */ 326 public Boolean getFeatureDefault(String featureId) { 327 for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { 328 if (RECOGNIZED_FEATURES[i].equals(featureId)) { 329 return FEATURE_DEFAULTS[i]; 330 } 331 } 332 return null; 333 } // getFeatureDefault(String):Boolean 334 335 /** 336 * Returns the default state for a property, or null if this 337 * component does not want to report a default value for this 338 * property. 339 * 340 * @param propertyId The property identifier. 341 * 342 * @since Xerces 2.2.0 343 */ 344 public Object getPropertyDefault(String propertyId) { 345 for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { 346 if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { 347 return PROPERTY_DEFAULTS[i]; 348 } 349 } 350 return null; 351 } // getPropertyDefault(String):Object 352 353 // 354 // XMLDocumentSource methods 355 // 356 357 /** Sets the document handler to receive information about the document. */ 358 public void setDocumentHandler(XMLDocumentHandler documentHandler) { 359 fDocumentHandler = documentHandler; 360 } // setDocumentHandler(XMLDocumentHandler) 361 362 /** Returns the document handler */ 363 public XMLDocumentHandler getDocumentHandler() { 364 return fDocumentHandler; 365 } // setDocumentHandler(XMLDocumentHandler) 366 367 368 // 369 // XMLDocumentHandler methods 370 // 371 372 /** Sets the document source */ 373 public void setDocumentSource(XMLDocumentSource source){ 374 fDocumentSource = source; 375 } // setDocumentSource 376 377 /** Returns the document source */ 378 public XMLDocumentSource getDocumentSource (){ 379 return fDocumentSource; 380 } // getDocumentSource 381 382 383 /** 384 * This method notifies the start of a general entity. 385 * <p> 386 * <strong>Note:</strong> This method is not called for entity references 387 * appearing as part of attribute values. 388 * 389 * @param name The name of the general entity. 390 * @param identifier The resource identifier. 391 * @param encoding The auto-detected IANA encoding name of the entity 392 * stream. This value will be null in those situations 393 * where the entity encoding is not auto-detected (e.g. 394 * internal entities or a document entity that is 395 * parsed from a java.io.Reader). 396 * @param augs Additional information that may include infoset augmentations 397 * 398 * @exception XNIException Thrown by handler to signal an error. 399 */ 400 public void startGeneralEntity(String name, 401 XMLResourceIdentifier identifier, 402 String encoding, Augmentations augs) 403 throws XNIException { 404 if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { 405 fDocumentHandler.startGeneralEntity(name, identifier, encoding, augs); 406 } 407 } // startEntity(String,String,String,String,String) 408 409 /** 410 * Notifies of the presence of a TextDecl line in an entity. If present, 411 * this method will be called immediately following the startEntity call. 412 * <p> 413 * <strong>Note:</strong> This method will never be called for the 414 * document entity; it is only called for external general entities 415 * referenced in document content. 416 * <p> 417 * <strong>Note:</strong> This method is not called for entity references 418 * appearing as part of attribute values. 419 * 420 * @param version The XML version, or null if not specified. 421 * @param encoding The IANA encoding name of the entity. 422 * @param augs Additional information that may include infoset augmentations 423 * 424 * @throws XNIException Thrown by handler to signal an error. 425 */ 426 public void textDecl(String version, String encoding, Augmentations augs) 427 throws XNIException { 428 if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { 429 fDocumentHandler.textDecl(version, encoding, augs); 430 } 431 } // textDecl(String,String) 432 433 /** 434 * The start of the document. 435 * 436 * @param locator The system identifier of the entity if the entity 437 * is external, null otherwise. 438 * @param encoding The auto-detected IANA encoding name of the entity 439 * stream. This value will be null in those situations 440 * where the entity encoding is not auto-detected (e.g. 441 * internal entities or a document entity that is 442 * parsed from a java.io.Reader). 443 * @param namespaceContext 444 * The namespace context in effect at the 445 * start of this document. 446 * This object represents the current context. 447 * Implementors of this class are responsible 448 * for copying the namespace bindings from the 449 * the current context (and its parent contexts) 450 * if that information is important. 451 * @param augs Additional information that may include infoset augmentations 452 * 453 * @throws XNIException Thrown by handler to signal an error. 454 */ 455 public void startDocument(XMLLocator locator, String encoding, 456 NamespaceContext namespaceContext, Augmentations augs) 457 throws XNIException { 458 fNamespaceContext = namespaceContext; 459 460 if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { 461 fDocumentHandler.startDocument(locator, encoding, namespaceContext, augs); 462 } 463 } // startDocument(XMLLocator,String) 464 465 /** 466 * Notifies of the presence of an XMLDecl line in the document. If 467 * present, this method will be called immediately following the 468 * startDocument call. 469 * 470 * @param version The XML version. 471 * @param encoding The IANA encoding name of the document, or null if 472 * not specified. 473 * @param standalone The standalone value, or null if not specified. 474 * @param augs Additional information that may include infoset augmentations 475 * 476 * @throws XNIException Thrown by handler to signal an error. 477 */ 478 public void xmlDecl(String version, String encoding, String standalone, Augmentations augs) 479 throws XNIException { 480 if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { 481 fDocumentHandler.xmlDecl(version, encoding, standalone, augs); 482 } 483 } // xmlDecl(String,String,String) 484 485 /** 486 * Notifies of the presence of the DOCTYPE line in the document. 487 * 488 * @param rootElement The name of the root element. 489 * @param publicId The public identifier if an external DTD or null 490 * if the external DTD is specified using SYSTEM. 491 * @param systemId The system identifier if an external DTD, null 492 * otherwise. 493 * @param augs Additional information that may include infoset augmentations 494 * 495 * @throws XNIException Thrown by handler to signal an error. 496 */ 497 public void doctypeDecl(String rootElement, 498 String publicId, String systemId, Augmentations augs) 499 throws XNIException { 500 if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { 501 fDocumentHandler.doctypeDecl(rootElement, publicId, systemId, augs); 502 } 503 } // doctypeDecl(String,String,String) 504 505 /** 506 * A comment. 507 * 508 * @param text The text in the comment. 509 * @param augs Additional information that may include infoset augmentations 510 * 511 * @throws XNIException Thrown by application to signal an error. 512 */ 513 public void comment(XMLString text, Augmentations augs) throws XNIException { 514 if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { 515 fDocumentHandler.comment(text, augs); 516 } 517 } // comment(XMLString) 518 519 /** 520 * A processing instruction. Processing instructions consist of a 521 * target name and, optionally, text data. The data is only meaningful 522 * to the application. 523 * <p> 524 * Typically, a processing instruction's data will contain a series 525 * of pseudo-attributes. These pseudo-attributes follow the form of 526 * element attributes but are <strong>not</strong> parsed or presented 527 * to the application as anything other than text. The application is 528 * responsible for parsing the data. 529 * 530 * @param target The target. 531 * @param data The data or null if none specified. 532 * @param augs Additional information that may include infoset augmentations 533 * 534 * @throws XNIException Thrown by handler to signal an error. 535 */ 536 public void processingInstruction(String target, XMLString data, Augmentations augs) 537 throws XNIException { 538 if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { 539 fDocumentHandler.processingInstruction(target, data, augs); 540 } 541 } // processingInstruction(String,XMLString) 542 543 544 /** 545 * Binds the namespaces. This method will handle calling the 546 * document handler to start the prefix mappings. 547 * <p> 548 * <strong>Note:</strong> This method makes use of the 549 * fAttributeQName variable. Any contents of the variable will 550 * be destroyed. Caller should copy the values out of this 551 * temporary variable before calling this method. 552 * 553 * @param element The name of the element. 554 * @param attributes The element attributes. 555 * @param augs Additional information that may include infoset augmentations 556 * 557 * @throws XNIException Thrown by handler to signal an error. 558 */ 559 public void startElement(QName element, XMLAttributes attributes, Augmentations augs) 560 throws XNIException { 561 562 if (fNamespaces) { 563 handleStartElement(element, attributes, augs, false); 564 } 565 else if (fDocumentHandler != null) { 566 fDocumentHandler.startElement(element, attributes, augs); 567 } 568 569 570 } // startElement(QName,XMLAttributes) 571 572 /** 573 * An empty element. 574 * 575 * @param element The name of the element. 576 * @param attributes The element attributes. 577 * @param augs Additional information that may include infoset augmentations 578 * 579 * @throws XNIException Thrown by handler to signal an error. 580 */ 581 public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) 582 throws XNIException { 583 584 if (fNamespaces) { 585 handleStartElement(element, attributes, augs, true); 586 handleEndElement(element, augs, true); 587 } 588 else if (fDocumentHandler != null) { 589 fDocumentHandler.emptyElement(element, attributes, augs); 590 } 591 592 } // emptyElement(QName,XMLAttributes) 593 594 /** 595 * Character content. 596 * 597 * @param text The content. 598 * @param augs Additional information that may include infoset augmentations 599 * 600 * @throws XNIException Thrown by handler to signal an error. 601 */ 602 public void characters(XMLString text, Augmentations augs) throws XNIException { 603 if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { 604 fDocumentHandler.characters(text, augs); 605 } 606 } // characters(XMLString) 607 608 /** 609 * Ignorable whitespace. For this method to be called, the document 610 * source must have some way of determining that the text containing 611 * only whitespace characters should be considered ignorable. For 612 * example, the validator can determine if a length of whitespace 613 * characters in the document are ignorable based on the element 614 * content model. 615 * 616 * @param text The ignorable whitespace. 617 * @param augs Additional information that may include infoset augmentations 618 * 619 * @throws XNIException Thrown by handler to signal an error. 620 */ 621 public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException { 622 if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { 623 fDocumentHandler.ignorableWhitespace(text, augs); 624 } 625 } // ignorableWhitespace(XMLString) 626 627 /** 628 * The end of an element. 629 * 630 * @param element The name of the element. 631 * @param augs Additional information that may include infoset augmentations 632 * 633 * @throws XNIException Thrown by handler to signal an error. 634 */ 635 public void endElement(QName element, Augmentations augs) throws XNIException { 636 637 if (fNamespaces) { 638 handleEndElement(element, augs, false); 639 } 640 else if (fDocumentHandler != null) { 641 fDocumentHandler.endElement(element, augs); 642 } 643 644 } // endElement(QName) 645 646 /** 647 * The start of a CDATA section. 648 * @param augs Additional information that may include infoset augmentations 649 * 650 * @throws XNIException Thrown by handler to signal an error. 651 */ 652 public void startCDATA(Augmentations augs) throws XNIException { 653 if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { 654 fDocumentHandler.startCDATA(augs); 655 } 656 } // startCDATA() 657 658 /** 659 * The end of a CDATA section. 660 * @param augs Additional information that may include infoset augmentations 661 * 662 * @throws XNIException Thrown by handler to signal an error. 663 */ 664 public void endCDATA(Augmentations augs) throws XNIException { 665 if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { 666 fDocumentHandler.endCDATA(augs); 667 } 668 } // endCDATA() 669 670 /** 671 * The end of the document. 672 * @param augs Additional information that may include infoset augmentations 673 * 674 * @throws XNIException Thrown by handler to signal an error. 675 */ 676 public void endDocument(Augmentations augs) throws XNIException { 677 if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { 678 fDocumentHandler.endDocument(augs); 679 } 680 } // endDocument() 681 682 /** 683 * This method notifies the end of a general entity. 684 * <p> 685 * <strong>Note:</strong> This method is not called for entity references 686 * appearing as part of attribute values. 687 * 688 * @param name The name of the entity. 689 * @param augs Additional information that may include infoset augmentations 690 * 691 * @exception XNIException 692 * Thrown by handler to signal an error. 693 */ 694 public void endGeneralEntity(String name, Augmentations augs) throws XNIException { 695 if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { 696 fDocumentHandler.endGeneralEntity(name, augs); 697 } 698 } // endEntity(String) 699 700 // 701 // Protected methods 702 // 703 704 /** Handles start element. */ 705 protected void handleStartElement(QName element, XMLAttributes attributes, 706 Augmentations augs, 707 boolean isEmpty) throws XNIException { 708 709 // add new namespace context 710 fNamespaceContext.pushContext(); 711 712 if (element.prefix == XMLSymbols.PREFIX_XMLNS) { 713 fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, 714 "ElementXMLNSPrefix", 715 new Object[]{element.rawname}, 716 XMLErrorReporter.SEVERITY_FATAL_ERROR); 717 } 718 719 // search for new namespace bindings 720 int length = attributes.getLength(); 721 for (int i = 0; i < length; i++) { 722 String localpart = attributes.getLocalName(i); 723 String prefix = attributes.getPrefix(i); 724 // when it's of form xmlns="..." or xmlns:prefix="...", 725 // it's a namespace declaration. but prefix:xmlns="..." isn't. 726 if (prefix == XMLSymbols.PREFIX_XMLNS || 727 prefix == XMLSymbols.EMPTY_STRING && localpart == XMLSymbols.PREFIX_XMLNS) { 728 729 // get the internalized value of this attribute 730 String uri = fSymbolTable.addSymbol(attributes.getValue(i)); 731 732 // 1. "xmlns" can't be bound to any namespace 733 if (prefix == XMLSymbols.PREFIX_XMLNS && localpart == XMLSymbols.PREFIX_XMLNS) { 734 fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, 735 "CantBindXMLNS", 736 new Object[]{attributes.getQName(i)}, 737 XMLErrorReporter.SEVERITY_FATAL_ERROR); 738 } 739 740 // 2. the namespace for "xmlns" can't be bound to any prefix 741 if (uri == NamespaceContext.XMLNS_URI) { 742 fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, 743 "CantBindXMLNS", 744 new Object[]{attributes.getQName(i)}, 745 XMLErrorReporter.SEVERITY_FATAL_ERROR); 746 } 747 748 // 3. "xml" can't be bound to any other namespace than it's own 749 if (localpart == XMLSymbols.PREFIX_XML) { 750 if (uri != NamespaceContext.XML_URI) { 751 fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, 752 "CantBindXML", 753 new Object[]{attributes.getQName(i)}, 754 XMLErrorReporter.SEVERITY_FATAL_ERROR); 755 } 756 } 757 // 4. the namespace for "xml" can't be bound to any other prefix 758 else { 759 if (uri ==NamespaceContext.XML_URI) { 760 fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, 761 "CantBindXML", 762 new Object[]{attributes.getQName(i)}, 763 XMLErrorReporter.SEVERITY_FATAL_ERROR); 764 } 765 } 766 767 prefix = localpart != XMLSymbols.PREFIX_XMLNS ? localpart : XMLSymbols.EMPTY_STRING; 768 769 // http://www.w3.org/TR/1999/REC-xml-names-19990114/#dt-prefix 770 // We should only report an error if there is a prefix, 771 // that is, the local part is not "xmlns". -SG 772 // Since this is an error condition in XML 1.0, 773 // and should be relatively uncommon in XML 1.1, 774 // making this test into a method call to reuse code 775 // should be acceptable. - NG 776 if(prefixBoundToNullURI(uri, localpart)) { 777 fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, 778 "EmptyPrefixedAttName", 779 new Object[]{attributes.getQName(i)}, 780 XMLErrorReporter.SEVERITY_FATAL_ERROR); 781 continue; 782 } 783 784 // declare prefix in context 785 fNamespaceContext.declarePrefix(prefix, uri.length() != 0 ? uri : null); 786 787 } 788 } 789 790 // bind the element 791 String prefix = element.prefix != null 792 ? element.prefix : XMLSymbols.EMPTY_STRING; 793 element.uri = fNamespaceContext.getURI(prefix); 794 if (element.prefix == null && element.uri != null) { 795 element.prefix = XMLSymbols.EMPTY_STRING; 796 } 797 if (element.prefix != null && element.uri == null) { 798 fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, 799 "ElementPrefixUnbound", 800 new Object[]{element.prefix, element.rawname}, 801 XMLErrorReporter.SEVERITY_FATAL_ERROR); 802 } 803 804 // bind the attributes 805 for (int i = 0; i < length; i++) { 806 attributes.getName(i, fAttributeQName); 807 String aprefix = fAttributeQName.prefix != null 808 ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING; 809 String arawname = fAttributeQName.rawname; 810 if (arawname == XMLSymbols.PREFIX_XMLNS) { 811 fAttributeQName.uri = fNamespaceContext.getURI(XMLSymbols.PREFIX_XMLNS); 812 attributes.setName(i, fAttributeQName); 813 } 814 else if (aprefix != XMLSymbols.EMPTY_STRING) { 815 fAttributeQName.uri = fNamespaceContext.getURI(aprefix); 816 if (fAttributeQName.uri == null) { 817 fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, 818 "AttributePrefixUnbound", 819 new Object[]{element.rawname,arawname,aprefix}, 820 XMLErrorReporter.SEVERITY_FATAL_ERROR); 821 } 822 attributes.setName(i, fAttributeQName); 823 } 824 } 825 826 // verify that duplicate attributes don't exist 827 // Example: <foo xmlns:a='NS' xmlns:b='NS' a:attr='v1' b:attr='v2'/> 828 int attrCount = attributes.getLength(); 829 for (int i = 0; i < attrCount - 1; i++) { 830 String auri = attributes.getURI(i); 831 if (auri == null || auri == NamespaceContext.XMLNS_URI) { 832 continue; 833 } 834 String alocalpart = attributes.getLocalName(i); 835 for (int j = i + 1; j < attrCount; j++) { 836 String blocalpart = attributes.getLocalName(j); 837 String buri = attributes.getURI(j); 838 if (alocalpart == blocalpart && auri == buri) { 839 fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, 840 "AttributeNSNotUnique", 841 new Object[]{element.rawname,alocalpart, auri}, 842 XMLErrorReporter.SEVERITY_FATAL_ERROR); 843 } 844 } 845 } 846 847 // call handler 848 if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { 849 if (isEmpty) { 850 fDocumentHandler.emptyElement(element, attributes, augs); 851 } 852 else { 853 fDocumentHandler.startElement(element, attributes, augs); 854 } 855 } 856 857 858 } // handleStartElement(QName,XMLAttributes,boolean) 859 860 /** Handles end element. */ 861 protected void handleEndElement(QName element, Augmentations augs, boolean isEmpty) 862 throws XNIException { 863 864 // bind element 865 String eprefix = element.prefix != null ? element.prefix : XMLSymbols.EMPTY_STRING; 866 element.uri = fNamespaceContext.getURI(eprefix); 867 if (element.uri != null) { 868 element.prefix = eprefix; 869 } 870 871 // call handlers 872 if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { 873 if (!isEmpty) { 874 fDocumentHandler.endElement(element, augs); 875 } 876 } 877 878 // pop context 879 fNamespaceContext.popContext(); 880 881 } // handleEndElement(QName,boolean) 882 883 // returns true iff the given prefix is bound to "" *and* 884 // this is disallowed by the version of XML namespaces in use. 885 protected boolean prefixBoundToNullURI(String uri, String localpart) { 886 return (uri == XMLSymbols.EMPTY_STRING && localpart != XMLSymbols.PREFIX_XMLNS); 887 } // prefixBoundToNullURI(String, String): boolean 888 889 } // class XMLNamespaceBinder