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