- /*
- * The Apache Software License, Version 1.1
- *
- *
- * Copyright (c) 1999-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.dom;
-
- import java.io.Serializable;
- import java.util.Vector;
-
- import org.w3c.dom.DOMException;
- import org.w3c.dom.NamedNodeMap;
- import org.w3c.dom.Node;
-
- /**
- * NamedNodeMaps represent collections of Nodes that can be accessed
- * by name. Entity and Notation nodes are stored in NamedNodeMaps
- * attached to the DocumentType. Attributes are placed in a NamedNodeMap
- * attached to the elem they're related too. However, because attributes
- * require more work, such as firing mutation events, they are stored in
- * a subclass of NamedNodeMapImpl.
- * <P>
- * Only one Node may be stored per name; attempting to
- * store another will replace the previous value.
- * <P>
- * NOTE: The "primary" storage key is taken from the NodeName attribute of the
- * node. The "secondary" storage key is the namespaceURI and localName, when
- * accessed by DOM level 2 nodes. All nodes, even DOM Level 2 nodes are stored
- * in a single Vector sorted by the primary "nodename" key.
- * <P>
- * NOTE: item()'s integer index does _not_ imply that the named nodes
- * must be stored in an array; that's only an access method. Note too
- * that these indices are "live"; if someone changes the map's
- * contents, the indices associated with nodes may change.
- * <P>
- *
- * @version $Id: NamedNodeMapImpl.java,v 1.35 2003/01/23 23:23:25 lmartin Exp $
- * @since PR-DOM-Level-1-19980818.
- */
- public class NamedNodeMapImpl
- implements NamedNodeMap, Serializable {
-
- //
- // Constants
- //
-
- /** Serialization version. */
- static final long serialVersionUID = -7039242451046758020L;
-
- //
- // Data
- //
-
- protected short flags;
-
- protected final static short READONLY = 0x1<<0;
- protected final static short CHANGED = 0x1<<1;
- protected final static short HASDEFAULTS = 0x1<<2;
-
- /** Nodes. */
- protected Vector nodes;
-
- protected NodeImpl ownerNode; // the node this map belongs to
-
- //
- // Constructors
- //
-
- /** Constructs a named node map. */
- protected NamedNodeMapImpl(NodeImpl ownerNode) {
- this.ownerNode = ownerNode;
- }
-
- //
- // NamedNodeMap methods
- //
-
- /**
- * Report how many nodes are currently stored in this NamedNodeMap.
- * Caveat: This is a count rather than an index, so the
- * highest-numbered node at any time can be accessed via
- * item(getLength()-1).
- */
- public int getLength() {
- return (nodes != null) ? nodes.size() : 0;
- }
-
- /**
- * Retrieve an item from the map by 0-based index.
- *
- * @param index Which item to retrieve. Note that indices are just an
- * enumeration of the current contents; they aren't guaranteed to be
- * stable, nor do they imply any promises about the order of the
- * NamedNodeMap's contents. In other words, DO NOT assume either that
- * index(i) will always refer to the same entry, or that there is any
- * stable ordering of entries... and be prepared for double-reporting
- * or skips as insertion and deletion occur.
- *
- * @return the node which currenly has the specified index, or null if index
- * is greater than or equal to getLength().
- */
- public Node item(int index) {
- return (nodes != null && index < nodes.size()) ?
- (Node)(nodes.elementAt(index)) : null;
- }
-
- /**
- * Retrieve a node by name.
- *
- * @param name Name of a node to look up.
- * @return the Node (of unspecified sub-class) stored with that name, or
- * null if no value has been assigned to that name.
- */
- public Node getNamedItem(String name) {
-
- int i = findNamePoint(name,0);
- return (i < 0) ? null : (Node)(nodes.elementAt(i));
-
- } // getNamedItem(String):Node
-
- /**
- * Introduced in DOM Level 2. <p>
- * Retrieves a node specified by local name and namespace URI.
- *
- * @param namespaceURI The namespace URI of the node to retrieve.
- * When it is null or an empty string, this
- * method behaves like getNamedItem.
- * @param localName The local name of the node to retrieve.
- * @return Node A Node (of any type) with the specified name, or null if the specified
- * name did not identify any node in the map.
- */
- public Node getNamedItemNS(String namespaceURI, String localName) {
-
- int i = findNamePoint(namespaceURI, localName);
- return (i < 0) ? null : (Node)(nodes.elementAt(i));
-
- } // getNamedItemNS(String,String):Node
-
- /**
- * Adds a node using its nodeName attribute.
- * As the nodeName attribute is used to derive the name which the node must be
- * stored under, multiple nodes of certain types (those that have a "special" string
- * value) cannot be stored as the names would clash. This is seen as preferable to
- * allowing nodes to be aliased.
- * @see org.w3c.dom.NamedNodeMap#setNamedItem
- * @return If the new Node replaces an existing node the replaced Node is returned,
- * otherwise null is returned.
- * @param arg
- * A node to store in a named node map. The node will later be
- * accessible using the value of the namespaceURI and localName
- * attribute of the node. If a node with those namespace URI and
- * local name is already present in the map, it is replaced by the new
- * one.
- * @exception org.w3c.dom.DOMException The exception description.
- */
- public Node setNamedItem(Node arg)
- throws DOMException {
-
- if (isReadOnly()) {
- String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
- throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
- }
- if (arg.getOwnerDocument() != ownerNode.ownerDocument()) {
- String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
- throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg);
- }
-
- int i = findNamePoint(arg.getNodeName(),0);
- NodeImpl previous = null;
- if (i >= 0) {
- previous = (NodeImpl) nodes.elementAt(i);
- nodes.setElementAt(arg,i);
- } else {
- i = -1 - i; // Insert point (may be end of list)
- if (null == nodes) {
- nodes = new Vector(5, 10);
- }
- nodes.insertElementAt(arg, i);
- }
- return previous;
-
- } // setNamedItem(Node):Node
-
- /**
- * Adds a node using its namespaceURI and localName.
- * @see org.w3c.dom.NamedNodeMap#setNamedItem
- * @return If the new Node replaces an existing node the replaced Node is returned,
- * otherwise null is returned.
- * @param arg A node to store in a named node map. The node will later be
- * accessible using the value of the namespaceURI and localName
- * attribute of the node. If a node with those namespace URI and
- * local name is already present in the map, it is replaced by the new
- * one.
- */
- public Node setNamedItemNS(Node arg)
- throws DOMException {
-
- if (isReadOnly()) {
- String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
- throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
- }
-
- if(arg.getOwnerDocument() != ownerNode.ownerDocument()) {
- String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
- throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg);
- }
-
- int i = findNamePoint(arg.getNamespaceURI(), arg.getLocalName());
- NodeImpl previous = null;
- if (i >= 0) {
- previous = (NodeImpl) nodes.elementAt(i);
- nodes.setElementAt(arg,i);
- } else {
- // If we can't find by namespaceURI, localName, then we find by
- // nodeName so we know where to insert.
- i = findNamePoint(arg.getNodeName(),0);
- if (i >=0) {
- previous = (NodeImpl) nodes.elementAt(i);
- nodes.insertElementAt(arg,i);
- } else {
- i = -1 - i; // Insert point (may be end of list)
- if (null == nodes) {
- nodes = new Vector(5, 10);
- }
- nodes.insertElementAt(arg, i);
- }
- }
- return previous;
-
- } // setNamedItem(Node):Node
-
- /**
- * Removes a node specified by name.
- * @param name The name of a node to remove.
- * @return The node removed from the map if a node with such a name exists.
- */
- /***/
- public Node removeNamedItem(String name)
- throws DOMException {
-
- if (isReadOnly()) {
- String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
- throw
- new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
- msg);
- }
- int i = findNamePoint(name,0);
- if (i < 0) {
- String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
- throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
- }
-
- NodeImpl n = (NodeImpl)nodes.elementAt(i);
- nodes.removeElementAt(i);
-
- return n;
-
- } // removeNamedItem(String):Node
-
- /**
- * Introduced in DOM Level 2. <p>
- * Removes a node specified by local name and namespace URI.
- * @param namespaceURI
- * The namespace URI of the node to remove.
- * When it is null or an empty string, this
- * method behaves like removeNamedItem.
- * @param The local name of the node to remove.
- * @return Node The node removed from the map if a node with such
- * a local name and namespace URI exists.
- * @throws NOT_FOUND_ERR: Raised if there is no node named
- * name in the map.
-
- */
- public Node removeNamedItemNS(String namespaceURI, String name)
- throws DOMException {
-
- if (isReadOnly()) {
- String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
- throw
- new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
- msg);
- }
- int i = findNamePoint(namespaceURI, name);
- if (i < 0) {
- String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
- throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
- }
-
- NodeImpl n = (NodeImpl)nodes.elementAt(i);
- nodes.removeElementAt(i);
-
- return n;
-
- } // removeNamedItem(String):Node
-
- //
- // Public methods
- //
-
- /**
- * Cloning a NamedNodeMap is a DEEP OPERATION; it always clones
- * all the nodes contained in the map.
- */
-
- public NamedNodeMapImpl cloneMap(NodeImpl ownerNode) {
- NamedNodeMapImpl newmap = new NamedNodeMapImpl(ownerNode);
- newmap.cloneContent(this);
- return newmap;
- }
-
- protected void cloneContent(NamedNodeMapImpl srcmap) {
- Vector srcnodes = srcmap.nodes;
- if (srcnodes != null) {
- int size = srcnodes.size();
- if (size != 0) {
- if (nodes == null) {
- nodes = new Vector(size);
- }
- nodes.setSize(size);
- for (int i = 0; i < size; ++i) {
- NodeImpl n = (NodeImpl) srcmap.nodes.elementAt(i);
- NodeImpl clone = (NodeImpl) n.cloneNode(true);
- clone.isSpecified(n.isSpecified());
- nodes.setElementAt(clone, i);
- }
- }
- }
- } // cloneMap():NamedNodeMapImpl
-
- //
- // Package methods
- //
-
- /**
- * Internal subroutine to allow read-only Nodes to make their contained
- * NamedNodeMaps readonly too. I expect that in fact the shallow
- * version of this operation will never be
- *
- * @param readOnly boolean true to make read-only, false to permit editing.
- * @param deep boolean true to pass this request along to the contained
- * nodes, false to only toggle the NamedNodeMap itself. I expect that
- * the shallow version of this operation will never be used, but I want
- * to design it in now, while I'm thinking about it.
- */
- void setReadOnly(boolean readOnly, boolean deep) {
- isReadOnly(readOnly);
- if (deep && nodes != null) {
- for (int i = nodes.size() - 1; i >= 0; i--) {
- ((NodeImpl) nodes.elementAt(i)).setReadOnly(readOnly,deep);
- }
- }
- } // setReadOnly(boolean,boolean)
-
- /**
- * Internal subroutine returns this NodeNameMap's (shallow) readOnly value.
- *
- */
- boolean getReadOnly() {
- return isReadOnly();
- } // getReadOnly()
-
-
- //
- // Protected methods
- //
-
- /**
- * NON-DOM
- * set the ownerDocument of this node, and the attributes it contains
- */
- void setOwnerDocument(CoreDocumentImpl doc) {
- if (nodes != null) {
- for (int i = 0; i < nodes.size(); i++) {
- ((NodeImpl)item(i)).setOwnerDocument(doc);
- }
- }
- }
-
- final boolean isReadOnly() {
- return (flags & READONLY) != 0;
- }
-
- final void isReadOnly(boolean value) {
- flags = (short) (value ? flags | READONLY : flags & ~READONLY);
- }
-
- final boolean changed() {
- return (flags & CHANGED) != 0;
- }
-
- final void changed(boolean value) {
- flags = (short) (value ? flags | CHANGED : flags & ~CHANGED);
- }
-
- final boolean hasDefaults() {
- return (flags & HASDEFAULTS) != 0;
- }
-
- final void hasDefaults(boolean value) {
- flags = (short) (value ? flags | HASDEFAULTS : flags & ~HASDEFAULTS);
- }
-
- //
- // Private methods
- //
-
- /**
- * Subroutine: Locate the named item, or the point at which said item
- * should be added.
- *
- * @param name Name of a node to look up.
- *
- * @return If positive or zero, the index of the found item.
- * If negative, index of the appropriate point at which to insert
- * the item, encoded as -1-index and hence reconvertable by subtracting
- * it from -1. (Encoding because I don't want to recompare the strings
- * but don't want to burn bytes on a datatype to hold a flagged value.)
- */
- protected int findNamePoint(String name, int start) {
-
- // Binary search
- int i = 0;
- if (nodes != null) {
- int first = start;
- int last = nodes.size() - 1;
-
- while (first <= last) {
- i = (first + last) / 2;
- int test = name.compareTo(((Node)(nodes.elementAt(i))).getNodeName());
- if (test == 0) {
- return i; // Name found
- }
- else if (test < 0) {
- last = i - 1;
- }
- else {
- first = i + 1;
- }
- }
-
- if (first > i) {
- i = first;
- }
- }
-
- return -1 - i; // not-found has to be encoded.
-
- } // findNamePoint(String):int
-
-
- /** This findNamePoint is for DOM Level 2 Namespaces.
- */
- protected int findNamePoint(String namespaceURI, String name) {
-
- if (nodes == null) return -1;
- if (name == null) return -1;
-
- // This is a linear search through the same nodes Vector.
- // The Vector is sorted on the DOM Level 1 nodename.
- // The DOM Level 2 NS keys are namespaceURI and Localname,
- // so we must linear search thru it.
- // In addition, to get this to work with nodes without any namespace
- // (namespaceURI and localNames are both null) we then use the nodeName
- // as a seconday key.
- for (int i = 0; i < nodes.size(); i++) {
- NodeImpl a = (NodeImpl)nodes.elementAt(i);
- String aNamespaceURI = a.getNamespaceURI();
- String aLocalName = a.getLocalName();
- if (namespaceURI == null) {
- if (aNamespaceURI == null
- &&
- (name.equals(aLocalName)
- ||
- (aLocalName == null && name.equals(a.getNodeName()))))
- return i;
- } else {
- if (namespaceURI.equals(aNamespaceURI)
- &&
- name.equals(aLocalName))
- return i;
- }
- }
- return -1;
- }
-
- // compare 2 nodes in the map. If a precedes b, return true, otherwise
- // return false
- protected boolean precedes(Node a, Node b) {
-
- if (nodes != null) {
- for (int i = 0; i < nodes.size(); i++) {
- Node n = (Node)nodes.elementAt(i);
- if (n==a) return true;
- if (n==b) return false;
- }
- }
-
- return false;
- }
-
-
- /**
- * NON-DOM: Remove attribute at specified index
- */
- protected void removeItem(int index) {
- if (nodes != null && index < nodes.size()){
- nodes.removeElementAt(index);
- }
- }
-
-
- protected Object getItem (int index){
- if (nodes !=null) {
- return nodes.elementAt(index);
- }
- return null;
- }
-
- protected int addItem (Node arg) {
- int i = findNamePoint(arg.getNamespaceURI(), arg.getLocalName());
- NodeImpl previous = null;
- if (i >= 0) {
- previous = (NodeImpl) nodes.elementAt(i);
- nodes.setElementAt(arg,i);
- } else {
- // If we can't find by namespaceURI, localName, then we find by
- // nodeName so we know where to insert.
- i = findNamePoint(arg.getNodeName(),0);
- if (i >=0) {
- previous = (NodeImpl) nodes.elementAt(i);
- nodes.insertElementAt(arg,i);
- } else {
- i = -1 - i; // Insert point (may be end of list)
- if (null == nodes) {
- nodes = new Vector(5, 10);
- }
- nodes.insertElementAt(arg, i);
- }
- }
- return i;
- }
-
- /**
- * NON-DOM: copy content of this map into the specified vector
- *
- * @param list Vector to copy information into.
- * @return A copy of this node named map
- */
- protected Vector cloneMap(Vector list){
- if (list == null) {
- list = new Vector(5, 10);
- }
- list.setSize(0);
- if (nodes != null) {
- for (int i=0; i<nodes.size(); i++) {
- list.insertElementAt(nodes.elementAt(i), i);
- }
- }
-
- return list;
- }
-
- protected int getNamedItemIndex(String namespaceURI, String localName) {
- return findNamePoint(namespaceURI, localName);
- }
-
- /**
- * NON-DOM remove all elements from this map
- */
- public void removeAll (){
- if (nodes != null) {
- nodes.removeAllElements();
- }
- }
-
-
- } // class NamedNodeMapImpl