| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * |
| * Copyright (c) 2000,2001 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 org.apache.xerces.util; |
| |
| import org.apache.xerces.xni.QName; |
| import org.apache.xerces.xni.XMLAttributes; |
| import org.apache.xerces.xni.XMLString; |
| import org.apache.xerces.xni.Augmentations; |
| |
| import org.xml.sax.AttributeList; |
| import org.xml.sax.Attributes; |
| |
| /** |
| * 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 org.apache.xerces.xni.XMLDocumentHandler#startElement |
| * |
| * @author Andy Clark, IBM |
| * @author Elena Litani, IBM |
| * |
| * @version $Id$ |
| */ |
| public class XMLAttributesImpl |
| implements XMLAttributes, AttributeList, Attributes { |
| |
| // |
| // Data |
| // |
| |
| // features |
| |
| /** Namespaces. */ |
| protected boolean fNamespaces = true; |
| |
| // data |
| |
| /** Attribute count. */ |
| protected int fLength; |
| |
| /** Attribute information. */ |
| protected Attribute[] fAttributes = new Attribute[4]; |
| |
| /** Augmentations information for each attribute |
| number of augmentations is equal to the number of attributes |
| */ |
| // XMLAttributes has no knowledge if any augmentations |
| // we attached to Augmentations. |
| protected Augmentations[] fAugmentations = new AugmentationsImpl[4]; |
| |
| // |
| // Constructors |
| // |
| |
| /** Default constructor. */ |
| public XMLAttributesImpl() { |
| for (int i = 0; i < fAttributes.length; i++) { |
| fAttributes[i] = new Attribute(); |
| fAugmentations[i] = new AugmentationsImpl(); |
| } |
| } // <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 attrName The attribute name. |
| * @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)". |
| * @param attrValue The attribute value. |
| * |
| * @return Returns the attribute index. |
| * |
| * @see #setNonNormalizedValue |
| * @see #setSpecified |
| */ |
| public int addAttribute(QName name, String type, String value) { |
| |
| // find attribute; create, if necessary |
| int index = name.uri != null && !name.uri.equals("") |
| ? getIndex(name.uri, name.localpart) |
| : getIndex(name.rawname); |
| if (index == -1) { |
| index = fLength; |
| if (fLength++ == fAttributes.length) { |
| Attribute[] attributes = new Attribute[fAttributes.length + 4]; |
| Augmentations[] augs = new AugmentationsImpl[fAttributes.length +4]; |
| System.arraycopy(fAttributes, 0, attributes, 0, fAttributes.length); |
| System.arraycopy(fAugmentations, 0, augs, 0, fAttributes.length); |
| for (int i = fAttributes.length; i < attributes.length; i++) { |
| attributes[i] = new Attribute(); |
| augs[i] = new AugmentationsImpl(); |
| } |
| fAttributes = attributes; |
| fAugmentations = augs; |
| } |
| } |
| |
| // clear augmentations |
| fAugmentations[index].clear(); |
| |
| // 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) { |
| if (attrIndex < fLength - 1) { |
| Attribute removedAttr = fAttributes[attrIndex]; |
| Augmentations removedAug = fAugmentations[attrIndex]; |
| System.arraycopy(fAttributes, attrIndex + 1, |
| fAttributes, attrIndex, fLength - attrIndex - 1); |
| |
| System.arraycopy(fAugmentations, attrIndex + 1, |
| fAugmentations, 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; |
| |
| fAugmentations[fLength-1] = removedAug; |
| } |
| 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; |
| } |
| String type = fAttributes[index].type; |
| if(type.indexOf('(') == 0 && type.lastIndexOf(')') == type.length()-1) { |
| return "NMTOKEN"; |
| } |
| return 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 ? 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 |
| |
| /** |
| * 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); |
| |
| if (index < 0 || index >= fLength) { |
| return null; |
| } |
| return fAugmentations[index]; |
| } |
| |
| /** |
| * 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 fAugmentations[attributeIndex]; |
| } |
| // |
| // 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; |
| |
| } // class Attribute |
| |
| } // class XMLAttributesImpl |