- /*
- * 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.dom;
-
- import java.util.Vector;
-
- import org.w3c.dom.DOMException;
- import org.w3c.dom.Node;
-
-
- /**
- * AttributeMap inherits from NamedNodeMapImpl and extends it to deal with the
- * specifics of storing attributes. These are:
- * <ul>
- * <li>managing ownership of attribute nodes
- * <li>managing default attributes
- * <li>firing mutation events
- * </ul>
- * <p>
- * This class doesn't directly support mutation events, however, it notifies
- * the document when mutations are performed so that the document class do so.
- *
- * @version $Id: AttributeMap.java,v 1.28 2004/02/16 23:09:35 mrglavas Exp $
- */
- public class AttributeMap extends NamedNodeMapImpl {
-
- /** Serialization version. */
- static final long serialVersionUID = 8872606282138665383L;
-
- //
- // Constructors
- //
-
- /** Constructs a named node map. */
- protected AttributeMap(ElementImpl ownerNode, NamedNodeMapImpl defaults) {
- super(ownerNode);
- if (defaults != null) {
- // initialize map with the defaults
- cloneContent(defaults);
- if (nodes != null) {
- hasDefaults(true);
- }
- }
- }
-
- /**
- * Adds an attribute using its nodeName attribute.
- * @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
- * An Attr node to store in this map.
- * @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);
- }
- if (arg.getNodeType() != Node.ATTRIBUTE_NODE) {
- String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null);
- throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, msg);
- }
-
- AttrImpl argn = (AttrImpl)arg;
-
- if (argn.isOwned()){
- if (argn.getOwnerElement() != ownerNode) {
- String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INUSE_ATTRIBUTE_ERR", null);
- throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR, msg);
- }
- // replacing an Attribute with itself does nothing
- return arg;
- }
-
- // set owner
- argn.ownerNode = ownerNode;
- argn.isOwned(true);
-
- int i = findNamePoint(arg.getNodeName(),0);
- AttrImpl previous = null;
- if (i >= 0) {
- previous = (AttrImpl) nodes.elementAt(i);
- nodes.setElementAt(arg,i);
- previous.ownerNode = ownerNode.ownerDocument();
- previous.isOwned(false);
- // make sure it won't be mistaken with defaults in case it's reused
- previous.isSpecified(true);
- } else {
- i = -1 - i; // Insert point (may be end of list)
- if (null == nodes) {
- nodes = new Vector(5, 10);
- }
- nodes.insertElementAt(arg, i);
- }
-
- // notify document
- ownerNode.ownerDocument().setAttrNode(argn, previous);
-
- // If the new attribute is not normalized,
- // the owning element is inherently not normalized.
- if (!argn.isNormalized()) {
- ownerNode.isNormalized(false);
- }
- return previous;
-
- } // setNamedItem(Node):Node
-
- /**
- * Adds an attribute 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.
- */
- 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);
- }
-
- if (arg.getNodeType() != Node.ATTRIBUTE_NODE) {
- String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null);
- throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, msg);
- }
- AttrImpl argn = (AttrImpl)arg;
-
- if (argn.isOwned()){
- if (argn.getOwnerElement() != ownerNode) {
- String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INUSE_ATTRIBUTE_ERR", null);
- throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR, msg);
- }
- // replacing an Attribute with itself does nothing
- return arg;
- }
-
- // set owner
- argn.ownerNode = ownerNode;
- argn.isOwned(true);
-
- int i = findNamePoint(argn.getNamespaceURI(), argn.getLocalName());
- AttrImpl previous = null;
- if (i >= 0) {
- previous = (AttrImpl) nodes.elementAt(i);
- nodes.setElementAt(arg,i);
- previous.ownerNode = ownerNode.ownerDocument();
- previous.isOwned(false);
- // make sure it won't be mistaken with defaults in case it's reused
- previous.isSpecified(true);
- } 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 = (AttrImpl) 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);
- }
- }
- // changed(true);
-
- // notify document
- ownerNode.ownerDocument().setAttrNode(argn, previous);
-
- // If the new attribute is not normalized,
- // the owning element is inherently not normalized.
- if (!argn.isNormalized()) {
- ownerNode.isNormalized(false);
- }
- return previous;
-
- } // setNamedItemNS(Node):Node
-
- /**
- * Removes an attribute specified by name.
- * @param name
- * The name of a node to remove. If the
- * removed attribute is known to have a default value, an
- * attribute immediately appears containing the default value
- * as well as the corresponding namespace URI, local name,
- * and prefix when applicable.
- * @return The node removed from the map if a node with such a name exists.
- * @throws NOT_FOUND_ERR: Raised if there is no node named
- * name in the map.
- */
- /***/
- public Node removeNamedItem(String name)
- throws DOMException {
- return internalRemoveNamedItem(name, true);
- }
-
- /**
- * Same as removeNamedItem except that it simply returns null if the
- * specified name is not found.
- */
- Node safeRemoveNamedItem(String name) {
- return internalRemoveNamedItem(name, false);
- }
-
-
- /**
- * NON-DOM: Remove the node object
- *
- * NOTE: Specifically removes THIS NODE -- not the node with this
- * name, nor the node with these contents. If node does not belong to
- * this named node map, we throw a DOMException.
- *
- * @param item The node to remove
- * @param addDefault true -- magically add default attribute
- * @return Removed node
- * @exception DOMException
- */
- protected Node removeItem(Node item, boolean addDefault)
- throws DOMException {
-
- int index = -1;
- if (nodes != null) {
- for (int i = 0; i < nodes.size(); i++) {
- if (nodes.elementAt(i) == item) {
- index = i;
- break;
- }
- }
- }
- if (index < 0) {
- String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
- throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
- }
-
- return remove((AttrImpl)item, index, addDefault);
- }
-
- /**
- * Internal removeNamedItem method allowing to specify whether an exception
- * must be thrown if the specified name is not found.
- */
- final protected Node internalRemoveNamedItem(String name, boolean raiseEx){
- 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) {
- if (raiseEx) {
- String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
- throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
- } else {
- return null;
- }
- }
-
- return remove((AttrImpl)nodes.elementAt(i), i, true);
-
- } // internalRemoveNamedItem(String,boolean):Node
-
- private final Node remove(AttrImpl attr, int index,
- boolean addDefault) {
-
- CoreDocumentImpl ownerDocument = ownerNode.ownerDocument();
- String name = attr.getNodeName();
- if (attr.isIdAttribute()) {
- ownerDocument.removeIdentifier(attr.getValue());
- }
-
- if (hasDefaults() && addDefault) {
- // If there's a default, add it instead
- NamedNodeMapImpl defaults =
- ((ElementImpl) ownerNode).getDefaultAttributes();
-
- Node d;
- if (defaults != null &&
- (d = defaults.getNamedItem(name)) != null &&
- findNamePoint(name, index+1) < 0) {
- NodeImpl clone = (NodeImpl)d.cloneNode(true);
- if (d.getLocalName() !=null){
- // we must rely on the name to find a default attribute
- // ("test:attr"), but while copying it from the DOCTYPE
- // we should not loose namespace URI that was assigned
- // to the attribute in the instance document.
- ((AttrNSImpl)clone).namespaceURI = attr.getNamespaceURI();
- }
- clone.ownerNode = ownerNode;
- clone.isOwned(true);
- clone.isSpecified(false);
-
- nodes.setElementAt(clone, index);
- if (attr.isIdAttribute()) {
- ownerDocument.putIdentifier(clone.getNodeValue(),
- (ElementImpl)ownerNode);
- }
- } else {
- nodes.removeElementAt(index);
- }
- } else {
- nodes.removeElementAt(index);
- }
-
- // changed(true);
-
- // remove reference to owner
- attr.ownerNode = ownerDocument;
- attr.isOwned(false);
-
- // make sure it won't be mistaken with defaults in case it's
- // reused
- attr.isSpecified(true);
- attr.isIdAttribute(false);
-
- // notify document
- ownerDocument.removedAttrNode(attr, ownerNode, name);
-
- return attr;
- }
-
- /**
- * Introduced in DOM Level 2. <p>
- * Removes an attribute 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. If the
- * removed attribute is known to have a default
- * value, an attribute immediately appears
- * containing the default value.
- * @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 {
- return internalRemoveNamedItemNS(namespaceURI, name, true);
- }
-
- /**
- * Same as removeNamedItem except that it simply returns null if the
- * specified local name and namespace URI is not found.
- */
- Node safeRemoveNamedItemNS(String namespaceURI, String name) {
- return internalRemoveNamedItemNS(namespaceURI, name, false);
- }
-
- /**
- * Internal removeNamedItemNS method allowing to specify whether an
- * exception must be thrown if the specified local name and namespace URI
- * is not found.
- */
- final protected Node internalRemoveNamedItemNS(String namespaceURI,
- String name,
- boolean raiseEx) {
- 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) {
- if (raiseEx) {
- String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
- throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
- } else {
- return null;
- }
- }
-
- AttrImpl n = (AttrImpl)nodes.elementAt(i);
- CoreDocumentImpl ownerDocument = ownerNode.ownerDocument();
-
- if (n.isIdAttribute()) {
- ownerDocument.removeIdentifier(n.getValue());
- }
- // If there's a default, add it instead
- String nodeName = n.getNodeName();
- if (hasDefaults()) {
- NamedNodeMapImpl defaults = ((ElementImpl) ownerNode).getDefaultAttributes();
- Node d;
- if (defaults != null
- && (d = defaults.getNamedItem(nodeName)) != null)
- {
- int j = findNamePoint(nodeName,0);
- if (j>=0 && findNamePoint(nodeName, j+1) < 0) {
- NodeImpl clone = (NodeImpl)d.cloneNode(true);
- clone.ownerNode = ownerNode;
- if (d.getLocalName() != null) {
- // we must rely on the name to find a default attribute
- // ("test:attr"), but while copying it from the DOCTYPE
- // we should not loose namespace URI that was assigned
- // to the attribute in the instance document.
- ((AttrNSImpl)clone).namespaceURI = namespaceURI;
- }
- clone.isOwned(true);
- clone.isSpecified(false);
- nodes.setElementAt(clone, i);
- if (clone.isIdAttribute()) {
- ownerDocument.putIdentifier(clone.getNodeValue(),
- (ElementImpl)ownerNode);
- }
- } else {
- nodes.removeElementAt(i);
- }
- } else {
- nodes.removeElementAt(i);
- }
- } else {
- nodes.removeElementAt(i);
- }
-
- // changed(true);
-
- // remove reference to owner
- n.ownerNode = ownerDocument;
- n.isOwned(false);
- // make sure it won't be mistaken with defaults in case it's
- // reused
- n.isSpecified(true);
- // update id table if needed
- n.isIdAttribute(false);
-
- // notify document
- ownerDocument.removedAttrNode(n, ownerNode, name);
-
- return n;
-
- } // internalRemoveNamedItemNS(String,String,boolean):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) {
- AttributeMap newmap =
- new AttributeMap((ElementImpl) ownerNode, null);
- newmap.hasDefaults(hasDefaults());
- newmap.cloneContent(this);
- return newmap;
- } // cloneMap():AttributeMap
-
- /**
- * Override parent's method to set the ownerNode correctly
- */
- 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) srcnodes.elementAt(i);
- NodeImpl clone = (NodeImpl) n.cloneNode(true);
- clone.isSpecified(n.isSpecified());
- nodes.setElementAt(clone, i);
- clone.ownerNode = ownerNode;
- clone.isOwned(true);
- }
- }
- }
- } // cloneContent():AttributeMap
-
-
- /**
- * Move specified attributes from the given map to this one
- */
- void moveSpecifiedAttributes(AttributeMap srcmap) {
- int nsize = (srcmap.nodes != null) ? srcmap.nodes.size() : 0;
- for (int i = nsize - 1; i >= 0; i--) {
- AttrImpl attr = (AttrImpl) srcmap.nodes.elementAt(i);
- if (attr.isSpecified()) {
- srcmap.remove(attr, i, false);
- if (attr.getLocalName() != null) {
- setNamedItem(attr);
- }
- else {
- setNamedItemNS(attr);
- }
- }
- }
- } // moveSpecifiedAttributes(AttributeMap):void
-
-
- /**
- * Get this AttributeMap in sync with the given "defaults" map.
- * @param defaults The default attributes map to sync with.
- */
- protected void reconcileDefaults(NamedNodeMapImpl defaults) {
-
- // remove any existing default
- int nsize = (nodes != null) ? nodes.size() : 0;
- for (int i = nsize - 1; i >= 0; i--) {
- AttrImpl attr = (AttrImpl) nodes.elementAt(i);
- if (!attr.isSpecified()) {
- remove(attr, i, false);
- }
- }
- // add the new defaults
- if (defaults == null) {
- return;
- }
- if (nodes == null || nodes.size() == 0) {
- cloneContent(defaults);
- }
- else {
- int dsize = defaults.nodes.size();
- for (int n = 0; n < dsize; n++) {
- AttrImpl d = (AttrImpl) defaults.nodes.elementAt(n);
- int i = findNamePoint(d.getNodeName(), 0);
- if (i < 0) {
- i = -1 - i;
- NodeImpl clone = (NodeImpl) d.cloneNode(true);
- clone.ownerNode = ownerNode;
- clone.isOwned(true);
- clone.isSpecified(false);
- nodes.insertElementAt(clone, i);
- }
- }
- }
-
- } // reconcileDefaults()
-
- } // class AttributeMap