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