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