- /*
- * The Apache Software License, Version 1.1
- *
- *
- * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
- * reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The end-user documentation included with the redistribution,
- * if any, must include the following acknowledgment:
- * "This product includes software developed by the
- * Apache Software Foundation (http://www.apache.org/)."
- * Alternately, this acknowledgment may appear in the software itself,
- * if and wherever such third-party acknowledgments normally appear.
- *
- * 4. The names "Xerces" and "Apache Software Foundation" must
- * not be used to endorse or promote products derived from this
- * software without prior written permission. For written
- * permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache",
- * nor may "Apache" appear in their name, without prior written
- * permission of the Apache Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation and was
- * originally based on software copyright (c) 1999, International
- * Business Machines, Inc., http://www.apache.org. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- */
-
- package com.sun.org.apache.xerces.internal.util;
-
- import com.sun.org.apache.xerces.internal.xni.Augmentations;
- import com.sun.org.apache.xerces.internal.xni.QName;
- import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
-
- /**
- * The XMLAttributesImpl class is an implementation of the XMLAttributes
- * interface which defines a collection of attributes for an element.
- * In the parser, the document source would scan the entire start element
- * and collect the attributes. The attributes are communicated to the
- * document handler in the startElement method.
- * <p>
- * The attributes are read-write so that subsequent stages in the document
- * pipeline can modify the values or change the attributes that are
- * propogated to the next stage.
- *
- * @see com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler#startElement
- *
- * @author Andy Clark, IBM
- * @author Elena Litani, IBM
- * @author Michael Glavassevich, IBM
- *
- * @version $Id: XMLAttributesImpl.java,v 1.24 2004/01/19 22:12:10 mrglavas Exp $
- */
- public class XMLAttributesImpl
- implements XMLAttributes {
-
- //
- // Constants
- //
-
- /** Default table size. */
- protected static final int TABLE_SIZE = 101;
-
- /**
- * Threshold at which an instance is treated
- * as a large attribute list.
- */
- protected static final int SIZE_LIMIT = 20;
-
- //
- // Data
- //
-
- // features
-
- /** Namespaces. */
- protected boolean fNamespaces = true;
-
- // data
-
- /**
- * Usage count for the attribute table view.
- * Incremented each time all attributes are removed
- * when the attribute table view is in use.
- */
- protected int fLargeCount = 1;
-
- /** Attribute count. */
- protected int fLength;
-
- /** Attribute information. */
- protected Attribute[] fAttributes = new Attribute[4];
-
- /**
- * Hashtable of attribute information.
- * Provides an alternate view of the attribute specification.
- */
- protected Attribute[] fAttributeTableView;
-
- /**
- * Tracks whether each chain in the hash table is stale
- * with respect to the current state of this object.
- * A chain is stale if its state is not the same as the number
- * of times the attribute table view has been used.
- */
- protected int[] fAttributeTableViewChainState;
-
- /**
- * Actual number of buckets in the table view.
- */
- protected int fTableViewBuckets;
-
- /**
- * Indicates whether the table view contains consistent data.
- */
- protected boolean fIsTableViewConsistent;
-
- //
- // Constructors
- //
-
- /** Default constructor. */
- public XMLAttributesImpl() {
- this(TABLE_SIZE);
- }
-
- /**
- * @param tableSize initial size of table view
- */
- public XMLAttributesImpl(int tableSize) {
- fTableViewBuckets = tableSize;
- for (int i = 0; i < fAttributes.length; i++) {
- fAttributes[i] = new Attribute();
- }
- } // <init>()
-
- //
- // Public methods
- //
-
- /**
- * Sets whether namespace processing is being performed. This state
- * is needed to return the correct value from the getLocalName method.
- *
- * @param namespaces True if namespace processing is turned on.
- *
- * @see #getLocalName
- */
- public void setNamespaces(boolean namespaces) {
- fNamespaces = namespaces;
- } // setNamespaces(boolean)
-
- //
- // XMLAttributes methods
- //
-
- /**
- * Adds an attribute. The attribute's non-normalized value of the
- * attribute will have the same value as the attribute value until
- * set using the <code>setNonNormalizedValue</code> method. Also,
- * the added attribute will be marked as specified in the XML instance
- * document unless set otherwise using the <code>setSpecified</code>
- * method.
- * <p>
- * <strong>Note:</strong> If an attribute of the same name already
- * exists, the old values for the attribute are replaced by the new
- * values.
- *
- * @param name The attribute name.
- * @param type The attribute type. The type name is determined by
- * the type specified for this attribute in the DTD.
- * For example: "CDATA", "ID", "NMTOKEN", etc. However,
- * attributes of type enumeration will have the type
- * value specified as the pipe ('|') separated list of
- * the enumeration values prefixed by an open
- * parenthesis and suffixed by a close parenthesis.
- * For example: "(true|false)".
- * @param value The attribute value.
- *
- * @return Returns the attribute index.
- *
- * @see #setNonNormalizedValue
- * @see #setSpecified
- */
- public int addAttribute(QName name, String type, String value) {
-
- int index;
- if (fLength < SIZE_LIMIT) {
- index = name.uri != null && !name.uri.equals("")
- ? getIndexFast(name.uri, name.localpart)
- : getIndexFast(name.rawname);
-
- if (index == -1) {
- index = fLength;
- if (fLength++ == fAttributes.length) {
- Attribute[] attributes = new Attribute[fAttributes.length + 4];
- System.arraycopy(fAttributes, 0, attributes, 0, fAttributes.length);
- for (int i = fAttributes.length; i < attributes.length; i++) {
- attributes[i] = new Attribute();
- }
- fAttributes = attributes;
- }
- }
- }
- else if (name.uri == null ||
- name.uri.length() == 0 ||
- (index = getIndexFast(name.uri, name.localpart)) == -1) {
-
- /**
- * If attributes were removed from the list after the table
- * becomes in use this isn't reflected in the table view. It's
- * assumed that once a user starts removing attributes they're
- * not likely to add more. We only make the view consistent if
- * the user of this class adds attributes, removes them, and
- * then adds more.
- */
- if (!fIsTableViewConsistent || fLength == SIZE_LIMIT) {
- prepareAndPopulateTableView();
- fIsTableViewConsistent = true;
- }
-
- int bucket = getTableViewBucket(name.rawname);
-
- // The chain is stale.
- // This must be a unique attribute.
- if (fAttributeTableViewChainState[bucket] != fLargeCount) {
- index = fLength;
- if (fLength++ == fAttributes.length) {
- Attribute[] attributes = new Attribute[fAttributes.length << 1];
- System.arraycopy(fAttributes, 0, attributes, 0, fAttributes.length);
- for (int i = fAttributes.length; i < attributes.length; i++) {
- attributes[i] = new Attribute();
- }
- fAttributes = attributes;
- }
-
- // Update table view.
- fAttributeTableViewChainState[bucket] = fLargeCount;
- fAttributes[index].next = null;
- fAttributeTableView[bucket] = fAttributes[index];
- }
- // This chain is active.
- // We need to check if any of the attributes has the same rawname.
- else {
- // Search the table.
- Attribute found = fAttributeTableView[bucket];
- while (found != null) {
- if (found.name.rawname == name.rawname) {
- break;
- }
- found = found.next;
- }
- // This attribute is unique.
- if (found == null) {
- index = fLength;
- if (fLength++ == fAttributes.length) {
- Attribute[] attributes = new Attribute[fAttributes.length << 1];
- System.arraycopy(fAttributes, 0, attributes, 0, fAttributes.length);
- for (int i = fAttributes.length; i < attributes.length; i++) {
- attributes[i] = new Attribute();
- }
- fAttributes = attributes;
- }
-
- // Update table view
- fAttributes[index].next = fAttributeTableView[bucket];
- fAttributeTableView[bucket] = fAttributes[index];
- }
- // Duplicate. We still need to find the index.
- else {
- index = getIndexFast(name.rawname);
- }
- }
- }
-
- // set values
- Attribute attribute = fAttributes[index];
- attribute.name.setValues(name);
- attribute.type = type;
- attribute.value = value;
- attribute.nonNormalizedValue = value;
- attribute.specified = false;
-
- // return
- return index;
-
- } // addAttribute(QName,String,XMLString)
-
- /**
- * Removes all of the attributes. This method will also remove all
- * entities associated to the attributes.
- */
- public void removeAllAttributes() {
- fLength = 0;
- } // removeAllAttributes()
-
- /**
- * Removes the attribute at the specified index.
- * <p>
- * <strong>Note:</strong> This operation changes the indexes of all
- * attributes following the attribute at the specified index.
- *
- * @param attrIndex The attribute index.
- */
- public void removeAttributeAt(int attrIndex) {
- fIsTableViewConsistent = false;
- if (attrIndex < fLength - 1) {
- Attribute removedAttr = fAttributes[attrIndex];
- System.arraycopy(fAttributes, attrIndex + 1,
- fAttributes, attrIndex, fLength - attrIndex - 1);
- // Make the discarded Attribute object available for re-use
- // by tucking it after the Attributes that are still in use
- fAttributes[fLength-1] = removedAttr;
- }
- fLength--;
- } // removeAttributeAt(int)
-
- /**
- * Sets the name of the attribute at the specified index.
- *
- * @param attrIndex The attribute index.
- * @param attrName The new attribute name.
- */
- public void setName(int attrIndex, QName attrName) {
- fAttributes[attrIndex].name.setValues(attrName);
- } // setName(int,QName)
-
- /**
- * Sets the fields in the given QName structure with the values
- * of the attribute name at the specified index.
- *
- * @param attrIndex The attribute index.
- * @param attrName The attribute name structure to fill in.
- */
- public void getName(int attrIndex, QName attrName) {
- attrName.setValues(fAttributes[attrIndex].name);
- } // getName(int,QName)
-
- /**
- * Sets the type of the attribute at the specified index.
- *
- * @param attrIndex The attribute index.
- * @param attrType The attribute type. The type name is determined by
- * the type specified for this attribute in the DTD.
- * For example: "CDATA", "ID", "NMTOKEN", etc. However,
- * attributes of type enumeration will have the type
- * value specified as the pipe ('|') separated list of
- * the enumeration values prefixed by an open
- * parenthesis and suffixed by a close parenthesis.
- * For example: "(true|false)".
- */
- public void setType(int attrIndex, String attrType) {
- fAttributes[attrIndex].type = attrType;
- } // setType(int,String)
-
- /**
- * Sets the value of the attribute at the specified index. This
- * method will overwrite the non-normalized value of the attribute.
- *
- * @param attrIndex The attribute index.
- * @param attrValue The new attribute value.
- *
- * @see #setNonNormalizedValue
- */
- public void setValue(int attrIndex, String attrValue) {
- Attribute attribute = fAttributes[attrIndex];
- attribute.value = attrValue;
- attribute.nonNormalizedValue = attrValue;
- } // setValue(int,String)
-
- /**
- * Sets the non-normalized value of the attribute at the specified
- * index.
- *
- * @param attrIndex The attribute index.
- * @param attrValue The new non-normalized attribute value.
- */
- public void setNonNormalizedValue(int attrIndex, String attrValue) {
- if (attrValue == null) {
- attrValue = fAttributes[attrIndex].value;
- }
- fAttributes[attrIndex].nonNormalizedValue = attrValue;
- } // setNonNormalizedValue(int,String)
-
- /**
- * Returns the non-normalized value of the attribute at the specified
- * index. If no non-normalized value is set, this method will return
- * the same value as the <code>getValue(int)</code> method.
- *
- * @param attrIndex The attribute index.
- */
- public String getNonNormalizedValue(int attrIndex) {
- String value = fAttributes[attrIndex].nonNormalizedValue;
- return value;
- } // getNonNormalizedValue(int):String
-
- /**
- * Sets whether an attribute is specified in the instance document
- * or not.
- *
- * @param attrIndex The attribute index.
- * @param specified True if the attribute is specified in the instance
- * document.
- */
- public void setSpecified(int attrIndex, boolean specified) {
- fAttributes[attrIndex].specified = specified;
- } // setSpecified(int,boolean)
-
- /**
- * Returns true if the attribute is specified in the instance document.
- *
- * @param attrIndex The attribute index.
- */
- public boolean isSpecified(int attrIndex) {
- return fAttributes[attrIndex].specified;
- } // isSpecified(int):boolean
-
- //
- // AttributeList and Attributes methods
- //
-
- /**
- * Return the number of attributes in the list.
- *
- * <p>Once you know the number of attributes, you can iterate
- * through the list.</p>
- *
- * @return The number of attributes in the list.
- */
- public int getLength() {
- return fLength;
- } // getLength():int
-
- /**
- * Look up an attribute's type by index.
- *
- * <p>The attribute type is one of the strings "CDATA", "ID",
- * "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", "ENTITIES",
- * or "NOTATION" (always in upper case).</p>
- *
- * <p>If the parser has not read a declaration for the attribute,
- * or if the parser does not report attribute types, then it must
- * return the value "CDATA" as stated in the XML 1.0 Recommentation
- * (clause 3.3.3, "Attribute-Value Normalization").</p>
- *
- * <p>For an enumerated attribute that is not a notation, the
- * parser will report the type as "NMTOKEN".</p>
- *
- * @param index The attribute index (zero-based).
- * @return The attribute's type as a string, or null if the
- * index is out of range.
- * @see #getLength
- */
- public String getType(int index) {
- if (index < 0 || index >= fLength) {
- return null;
- }
- return getReportableType(fAttributes[index].type);
- } // getType(int):String
-
- /**
- * Look up an attribute's type by XML 1.0 qualified name.
- *
- * <p>See {@link #getType(int) getType(int)} for a description
- * of the possible types.</p>
- *
- * @param qname The XML 1.0 qualified name.
- * @return The attribute type as a string, or null if the
- * attribute is not in the list or if qualified names
- * are not available.
- */
- public String getType(String qname) {
- int index = getIndex(qname);
- return index != -1 ? getReportableType(fAttributes[index].type) : null;
- } // getType(String):String
-
- /**
- * Look up an attribute's value by index.
- *
- * <p>If the attribute value is a list of tokens (IDREFS,
- * ENTITIES, or NMTOKENS), the tokens will be concatenated
- * into a single string with each token separated by a
- * single space.</p>
- *
- * @param index The attribute index (zero-based).
- * @return The attribute's value as a string, or null if the
- * index is out of range.
- * @see #getLength
- */
- public String getValue(int index) {
- if (index < 0 || index >= fLength) {
- return null;
- }
- return fAttributes[index].value;
- } // getValue(int):String
-
- /**
- * Look up an attribute's value by XML 1.0 qualified name.
- *
- * <p>See {@link #getValue(int) getValue(int)} for a description
- * of the possible values.</p>
- *
- * @param qname The XML 1.0 qualified name.
- * @return The attribute value as a string, or null if the
- * attribute is not in the list or if qualified names
- * are not available.
- */
- public String getValue(String qname) {
- int index = getIndex(qname);
- return index != -1 ? fAttributes[index].value : null;
- } // getValue(String):String
-
- //
- // AttributeList methods
- //
-
- /**
- * Return the name of an attribute in this list (by position).
- *
- * <p>The names must be unique: the SAX parser shall not include the
- * same attribute twice. Attributes without values (those declared
- * #IMPLIED without a value specified in the start tag) will be
- * omitted from the list.</p>
- *
- * <p>If the attribute name has a namespace prefix, the prefix
- * will still be attached.</p>
- *
- * @param i The index of the attribute in the list (starting at 0).
- * @return The name of the indexed attribute, or null
- * if the index is out of range.
- * @see #getLength
- */
- public String getName(int index) {
- if (index < 0 || index >= fLength) {
- return null;
- }
- return fAttributes[index].name.rawname;
- } // getName(int):String
-
- //
- // Attributes methods
- //
-
- /**
- * Look up the index of an attribute by XML 1.0 qualified name.
- *
- * @param qName The qualified (prefixed) name.
- * @return The index of the attribute, or -1 if it does not
- * appear in the list.
- */
- public int getIndex(String qName) {
- for (int i = 0; i < fLength; i++) {
- Attribute attribute = fAttributes[i];
- if (attribute.name.rawname != null &&
- attribute.name.rawname.equals(qName)) {
- return i;
- }
- }
- return -1;
- } // getIndex(String):int
-
- /**
- * Look up the index of an attribute by Namespace name.
- *
- * @param uri The Namespace URI, or null if
- * the name has no Namespace URI.
- * @param localName The attribute's local name.
- * @return The index of the attribute, or -1 if it does not
- * appear in the list.
- */
- public int getIndex(String uri, String localPart) {
- for (int i = 0; i < fLength; i++) {
- Attribute attribute = fAttributes[i];
- if (attribute.name.localpart != null &&
- attribute.name.localpart.equals(localPart) &&
- ((uri==attribute.name.uri) ||
- (uri!=null && attribute.name.uri!=null && attribute.name.uri.equals(uri))))
- {
- return i;
- }
- }
- return -1;
- } // getIndex(String,String):int
-
- /**
- * Look up an attribute's local name by index.
- *
- * @param index The attribute index (zero-based).
- * @return The local name, or the empty string if Namespace
- * processing is not being performed, or null
- * if the index is out of range.
- * @see #getLength
- */
- public String getLocalName(int index) {
- if (!fNamespaces) {
- return "";
- }
- if (index < 0 || index >= fLength) {
- return null;
- }
- return fAttributes[index].name.localpart;
- } // getLocalName(int):String
-
- /**
- * Look up an attribute's XML 1.0 qualified name by index.
- *
- * @param index The attribute index (zero-based).
- * @return The XML 1.0 qualified name, or the empty string
- * if none is available, or null if the index
- * is out of range.
- * @see #getLength
- */
- public String getQName(int index) {
- if (index < 0 || index >= fLength) {
- return null;
- }
- String rawname = fAttributes[index].name.rawname;
- return rawname != null ? rawname : "";
- } // getQName(int):String
-
- /**
- * Look up an attribute's type by Namespace name.
- *
- * <p>See {@link #getType(int) getType(int)} for a description
- * of the possible types.</p>
- *
- * @param uri The Namespace URI, or null if the
- * name has no Namespace URI.
- * @param localName The local name of the attribute.
- * @return The attribute type as a string, or null if the
- * attribute is not in the list or if Namespace
- * processing is not being performed.
- */
- public String getType(String uri, String localName) {
- if (!fNamespaces) {
- return null;
- }
- int index = getIndex(uri, localName);
- return index != -1 ? getType(index) : null;
- } // getType(String,String):String
- /**
- * Look up the index of an attribute by XML 1.0 qualified name.
- * <p>
- * <strong>Note:</strong>
- * This method uses reference comparison, and thus should
- * only be used internally. We cannot use this method in any
- * code exposed to users as they may not pass in unique strings.
- *
- * @param qName The qualified (prefixed) name.
- * @return The index of the attribute, or -1 if it does not
- * appear in the list.
- */
- public int getIndexFast(String qName) {
- for (int i = 0; i < fLength; ++i) {
- Attribute attribute = fAttributes[i];
- if (attribute.name.rawname == qName) {
- return i;
- }
- }
- return -1;
- } // getIndexFast(String):int
-
- /**
- * Adds an attribute. The attribute's non-normalized value of the
- * attribute will have the same value as the attribute value until
- * set using the <code>setNonNormalizedValue</code> method. Also,
- * the added attribute will be marked as specified in the XML instance
- * document unless set otherwise using the <code>setSpecified</code>
- * method.
- * <p>
- * This method differs from <code>addAttribute</code> in that it
- * does not check if an attribute of the same name already exists
- * in the list before adding it. In order to improve performance
- * of namespace processing, this method allows uniqueness checks
- * to be deferred until all the namespace information is available
- * after the entire attribute specification has been read.
- * <p>
- * <strong>Caution:</strong> If this method is called it should
- * not be mixed with calls to <code>addAttribute</code> unless
- * it has been determined that all the attribute names are unique.
- *
- * @param name the attribute name
- * @param type the attribute type
- * @param value the attribute value
- *
- * @see #setNonNormalizedValue
- * @see #setSpecified
- * @see #checkDuplicatesNS
- */
- public void addAttributeNS(QName name, String type, String value) {
- int index = fLength;
- if (fLength++ == fAttributes.length) {
- Attribute[] attributes;
- if (fLength < SIZE_LIMIT) {
- attributes = new Attribute[fAttributes.length + 4];
- }
- else {
- attributes = new Attribute[fAttributes.length << 1];
- }
- System.arraycopy(fAttributes, 0, attributes, 0, fAttributes.length);
- for (int i = fAttributes.length; i < attributes.length; i++) {
- attributes[i] = new Attribute();
- }
- fAttributes = attributes;
- }
-
- // set values
- Attribute attribute = fAttributes[index];
- attribute.name.setValues(name);
- attribute.type = type;
- attribute.value = value;
- attribute.nonNormalizedValue = value;
- attribute.specified = false;
-
- // clear augmentations
- attribute.augs.removeAllItems();
- }
-
- /**
- * Checks for duplicate expanded names (local part and namespace name
- * pairs) in the attribute specification. If a duplicate is found its
- * name is returned.
- * <p>
- * This should be called once all the in-scope namespaces for the element
- * enclosing these attributes is known, and after all the attributes
- * have gone through namespace binding.
- *
- * @return the name of a duplicate attribute found in the search,
- * otherwise null.
- */
- public QName checkDuplicatesNS() {
- // If the list is small check for duplicates using pairwise comparison.
- if (fLength <= SIZE_LIMIT) {
- for (int i = 0; i < fLength - 1; ++i) {
- Attribute att1 = fAttributes[i];
- for (int j = i + 1; j < fLength; ++j) {
- Attribute att2 = fAttributes[j];
- if (att1.name.localpart == att2.name.localpart &&
- att1.name.uri == att2.name.uri) {
- return att2.name;
- }
- }
- }
- }
- // If the list is large check duplicates using a hash table.
- else {
- // We don't want this table view to be read if someone calls
- // addAttribute so we invalidate it up front.
- fIsTableViewConsistent = false;
-
- prepareTableView();
-
- Attribute attr;
- int bucket;
-
- for (int i = fLength - 1; i >= 0; --i) {
- attr = fAttributes[i];
- bucket = getTableViewBucket(attr.name.localpart, attr.name.uri);
-
- // The chain is stale.
- // This must be a unique attribute.
- if (fAttributeTableViewChainState[bucket] != fLargeCount) {
- fAttributeTableViewChainState[bucket] = fLargeCount;
- attr.next = null;
- fAttributeTableView[bucket] = attr;
- }
- // This chain is active.
- // We need to check if any of the attributes has the same name.
- else {
- // Search the table.
- Attribute found = fAttributeTableView[bucket];
- while (found != null) {
- if (found.name.localpart == attr.name.localpart &&
- found.name.uri == attr.name.uri) {
- return attr.name;
- }
- found = found.next;
- }
-
- // Update table view
- attr.next = fAttributeTableView[bucket];
- fAttributeTableView[bucket] = attr;
- }
- }
- }
- return null;
- }
-
- /**
- * Look up the index of an attribute by Namespace name.
- * <p>
- * <strong>Note:</strong>
- * This method uses reference comparison, and thus should
- * only be used internally. We cannot use this method in any
- * code exposed to users as they may not pass in unique strings.
- *
- * @param uri The Namespace URI, or null if
- * the name has no Namespace URI.
- * @param localName The attribute's local name.
- * @return The index of the attribute, or -1 if it does not
- * appear in the list.
- */
- public int getIndexFast(String uri, String localPart) {
- for (int i = 0; i < fLength; ++i) {
- Attribute attribute = fAttributes[i];
- if (attribute.name.localpart == localPart &&
- attribute.name.uri == uri) {
- return i;
- }
- }
- return -1;
- } // getIndexFast(String,String):int
-
- /**
- * Returns the value passed in or NMTOKEN if it's an enumerated type.
- *
- * @param type attribute type
- * @return the value passed in or NMTOKEN if it's an enumerated type.
- */
- private String getReportableType(String type) {
-
- if (type.charAt(0) == '(') {
- return "NMTOKEN";
- }
- return type;
- }
-
- /**
- * Returns the position in the table view
- * where the given attribute name would be hashed.
- *
- * @param qname the attribute name
- * @return the position in the table view where the given attribute
- * would be hashed
- */
- protected int getTableViewBucket(String qname) {
- return (qname.hashCode() & 0x7FFFFFFF) % fTableViewBuckets;
- }
-
- /**
- * Returns the position in the table view
- * where the given attribute name would be hashed.
- *
- * @param localpart the local part of the attribute
- * @param uri the namespace name of the attribute
- * @return the position in the table view where the given attribute
- * would be hashed
- */
- protected int getTableViewBucket(String localpart, String uri) {
- if (uri == null) {
- return (localpart.hashCode() & 0x7FFFFFFF) % fTableViewBuckets;
- }
- else {
- return ((localpart.hashCode() + uri.hashCode())
- & 0x7FFFFFFF) % fTableViewBuckets;
- }
- }
-
- /**
- * Purges all elements from the table view.
- */
- protected void cleanTableView() {
- if (++fLargeCount < 0) {
- // Overflow. We actually need to visit the chain state array.
- if (fAttributeTableViewChainState != null) {
- for (int i = fTableViewBuckets - 1; i >= 0; --i) {
- fAttributeTableViewChainState[i] = 0;
- }
- }
- fLargeCount = 1;
- }
- }
-
- /**
- * Prepares the table view of the attributes list for use.
- */
- protected void prepareTableView() {
- if (fAttributeTableView == null) {
- fAttributeTableView = new Attribute[fTableViewBuckets];
- fAttributeTableViewChainState = new int[fTableViewBuckets];
- }
- else {
- cleanTableView();
- }
- }
-
- /**
- * Prepares the table view of the attributes list for use,
- * and populates it with the attributes which have been
- * previously read.
- */
- protected void prepareAndPopulateTableView() {
- prepareTableView();
- // Need to populate the hash table with the attributes we've scanned so far.
- Attribute attr;
- int bucket;
- for (int i = 0; i < fLength; ++i) {
- attr = fAttributes[i];
- bucket = getTableViewBucket(attr.name.rawname);
- if (fAttributeTableViewChainState[bucket] != fLargeCount) {
- fAttributeTableViewChainState[bucket] = fLargeCount;
- attr.next = null;
- fAttributeTableView[bucket] = attr;
- }
- else {
- // Update table view
- attr.next = fAttributeTableView[bucket];
- fAttributeTableView[bucket] = attr;
- }
- }
- }
-
-
- /**
- * Returns the prefix of the attribute at the specified index.
- *
- * @param index The index of the attribute.
- */
- public String getPrefix(int index) {
- if (index < 0 || index >= fLength) {
- return null;
- }
- String prefix = fAttributes[index].name.prefix;
- // REVISIT: The empty string is not entered in the symbol table!
- return prefix != null ? prefix : "";
- } // getPrefix(int):String
-
- /**
- * Look up an attribute's Namespace URI by index.
- *
- * @param index The attribute index (zero-based).
- * @return The Namespace URI
- * @see #getLength
- */
- public String getURI(int index) {
- if (index < 0 || index >= fLength) {
- return null;
- }
- String uri = fAttributes[index].name.uri;
- return uri;
- } // getURI(int):String
-
- /**
- * Look up an attribute's value by Namespace name.
- *
- * <p>See {@link #getValue(int) getValue(int)} for a description
- * of the possible values.</p>
- *
- * @param uri The Namespace URI, or null if the
- * @param localName The local name of the attribute.
- * @return The attribute value as a string, or null if the
- * attribute is not in the list.
- */
- public String getValue(String uri, String localName) {
- int index = getIndex(uri, localName);
- return index != -1 ? getValue(index) : null;
- } // getValue(String,String):String
-
-
- /**
- * Look up an augmentations by Namespace name.
- *
- * @param uri The Namespace URI, or null if the
- * @param localName The local name of the attribute.
- * @return Augmentations
- */
- public Augmentations getAugmentations (String uri, String localName) {
- int index = getIndex(uri, localName);
- return index != -1 ? fAttributes[index].augs : null;
- }
-
- /**
- * Look up an augmentation by XML 1.0 qualified name.
- * <p>
- *
- * @param qName The XML 1.0 qualified name.
- *
- * @return Augmentations
- *
- */
- public Augmentations getAugmentations(String qName){
- int index = getIndex(qName);
- return index != -1 ? fAttributes[index].augs : null;
- }
-
-
-
- /**
- * Look up an augmentations by attributes index.
- *
- * @param attributeIndex The attribute index.
- * @return Augmentations
- */
- public Augmentations getAugmentations (int attributeIndex){
- if (attributeIndex < 0 || attributeIndex >= fLength) {
- return null;
- }
- return fAttributes[attributeIndex].augs;
- }
-
- /**
- * Sets the augmentations of the attribute at the specified index.
- *
- * @param attrIndex The attribute index.
- * @param augs The augmentations.
- */
- public void setAugmentations(int attrIndex, Augmentations augs) {
- fAttributes[attrIndex].augs = augs;
- }
-
- /**
- * Sets the uri of the attribute at the specified index.
- *
- * @param attrIndex The attribute index.
- * @param uri Namespace uri
- */
- public void setURI(int attrIndex, String uri) {
- fAttributes[attrIndex].name.uri = uri;
- } // getURI(int,QName)
-
- //
- // Classes
- //
-
- /**
- * Attribute information.
- *
- * @author Andy Clark, IBM
- */
- static class Attribute {
-
- //
- // Data
- //
-
- // basic info
-
- /** Name. */
- public QName name = new QName();
-
- /** Type. */
- public String type;
-
- /** Value. */
- public String value;
-
- /** Non-normalized value. */
- public String nonNormalizedValue;
-
- /** Specified. */
- public boolean specified;
-
- /**
- * Augmentations information for this attribute.
- * XMLAttributes has no knowledge if any augmentations
- * were attached to Augmentations.
- */
- public Augmentations augs = new AugmentationsImpl();
-
- // Additional data for attribute table view
-
- /** Pointer to the next attribute in the chain. **/
- public Attribute next;
-
- } // class Attribute
-
- } // class XMLAttributesImpl