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