/* * Copyright 1999-2002,2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * $Id: NamedNodeMapImpl.cpp 176026 2004-09-08 13:57:07Z peiyongz $ */ #include "NamedNodeMapImpl.hpp" #include "NodeVector.hpp" #include "AttrImpl.hpp" #include "DOM_DOMException.hpp" #include "DocumentImpl.hpp" XERCES_CPP_NAMESPACE_BEGIN int NamedNodeMapImpl::gLiveNamedNodeMaps = 0; int NamedNodeMapImpl::gTotalNamedNodeMaps = 0; NamedNodeMapImpl::NamedNodeMapImpl(NodeImpl *ownerNod) { this->ownerNode=ownerNod; this->nodes = null; this->readOnly = false; this->refCount = 1; gLiveNamedNodeMaps++; gTotalNamedNodeMaps++; }; NamedNodeMapImpl::~NamedNodeMapImpl() { if (nodes) { // It is the responsibility of whoever was using the named node // map to do any cleanup on the nodes contained in the map // before deleting it. delete nodes; nodes = 0; } gLiveNamedNodeMaps--; }; void NamedNodeMapImpl::addRef(NamedNodeMapImpl *This) { if (This) ++This->refCount; }; NamedNodeMapImpl *NamedNodeMapImpl::cloneMap(NodeImpl *ownerNod) { MemoryManager* manager = ownerNod->getDocument()->getMemoryManager(); NamedNodeMapImpl *newmap = new (manager) NamedNodeMapImpl(ownerNod); if (nodes != null) { newmap->nodes = new (manager) NodeVector(nodes->size(), manager); for (unsigned int i = 0; i < nodes->size(); ++i) { NodeImpl *n = nodes->elementAt(i)->cloneNode(true); n->isSpecified(nodes->elementAt(i)->isSpecified()); n->ownerNode = ownerNod; n->isOwned(true); newmap->nodes->addElement(n); } } return newmap; }; // // removeAll - This function removes all elements from a named node map. // It is called from the destructors for Elements and DocumentTypes, // to remove the contents when the owning Element or DocType goes // away. The empty NamedNodeMap may persist if the user code // has a reference to it. // // AH Revist - the empty map should be made read-only, since // adding it was logically part of the [Element, DocumentType] // that has been deleted, and adding anything new to it would // be meaningless, and almost certainly an error. // void NamedNodeMapImpl::removeAll() { if (nodes) { for (int i=nodes->size()-1; i>=0; i--) { NodeImpl *n = nodes->elementAt(i); n->ownerNode = ownerNode->getOwnerDocument(); n->isOwned(false); if (n->nodeRefCount == 0) NodeImpl::deleteIf(n); } delete nodes; nodes = null; } } int NamedNodeMapImpl::findNamePoint(const DOMString &name) { // Binary search int i=0; if(nodes!=null) { int first=0,last=nodes->size()-1; while(first<=last) { i=(first+last)/2; int test = name.compareString(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; } /******************** // Linear search int i = 0; if (nodes != null) for (i = 0; i < nodes.size(); ++i) { int test = name.compareTo(((NodeImpl *) (nodes.elementAt(i))).getNodeName()); if (test == 0) return i; else if (test < 0) { break; // Found insertpoint } } *******************/ return -1 - i; // not-found has to be encoded. }; unsigned int NamedNodeMapImpl::getLength() { return (nodes != null) ? nodes->size() : 0; }; NodeImpl * NamedNodeMapImpl::getNamedItem(const DOMString &name) { int i=findNamePoint(name); return (i<0) ? null : (NodeImpl *)(nodes->elementAt(i)); }; NodeImpl * NamedNodeMapImpl::item(unsigned int index) { return (nodes != null && index < nodes->size()) ? (NodeImpl *) (nodes->elementAt(index)) : null; }; // // removeNamedItem() - Remove the named item, and return it. // The caller must arrange for deletion of the // returned item if its refcount has gone to zero - // we can't do it here because the caller would // never see the returned node. // NodeImpl * NamedNodeMapImpl::removeNamedItem(const DOMString &name) { if (readOnly) throw DOM_DOMException( DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null); int i=findNamePoint(name); NodeImpl *n = null; if(i<0) throw DOM_DOMException(DOM_DOMException::NOT_FOUND_ERR, null); n = (NodeImpl *) (nodes->elementAt(i)); nodes->removeElementAt(i); n->ownerNode = ownerNode->getOwnerDocument(); n->isOwned(false); return n; }; void NamedNodeMapImpl::removeRef(NamedNodeMapImpl *This) { if (This && --This->refCount == 0) delete This; }; // // setNamedItem() Put the item into the NamedNodeList by name. // If an item with the same name already was // in the list, replace it. Return the old // item, if there was one. // Caller is responsible for arranging for // deletion of the old item if its ref count is // zero. // NodeImpl * NamedNodeMapImpl::setNamedItem(NodeImpl * arg) { if(arg->getOwnerDocument() != ownerNode->getOwnerDocument()) throw DOM_DOMException(DOM_DOMException::WRONG_DOCUMENT_ERR,null); if (readOnly) throw DOM_DOMException(DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null); if ((arg->getNodeType() == DOM_Node::ATTRIBUTE_NODE) && arg->isOwned() && (arg->ownerNode != ownerNode)) throw DOM_DOMException(DOM_DOMException::INUSE_ATTRIBUTE_ERR,null); arg->ownerNode = ownerNode; arg->isOwned(true); int i=findNamePoint(arg->getNodeName()); NodeImpl * previous=null; if(i>=0) { previous = nodes->elementAt(i); nodes->setElementAt(arg,i); } else { i=-1-i; // Insert point (may be end of list) if(null==nodes) { MemoryManager* manager = ownerNode->getDocument()->getMemoryManager(); nodes=new (manager) NodeVector(manager); } nodes->insertElementAt(arg,i); } if (previous != null) { previous->ownerNode = ownerNode->getOwnerDocument(); previous->isOwned(false); } return previous; }; void NamedNodeMapImpl::setReadOnly(bool readOnl, bool deep) { this->readOnly=readOnl; if(deep && nodes!=null) { //Enumeration e=nodes->elements(); //while(e->hasMoreElements()) // ((NodeImpl)e->nextElement())->setReadOnly(readOnl,deep); int sz = nodes->size(); for (int i=0; ielementAt(i)->setReadOnly(readOnl, deep); } } }; //Introduced in DOM Level 2 int NamedNodeMapImpl::findNamePoint(const DOMString &namespaceURI, const DOMString &localName) { if (nodes == 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 secondary key. int i, len = nodes -> size(); for (i = 0; i < len; ++i) { NodeImpl *node = nodes -> elementAt(i); if (! node -> getNamespaceURI().equals(namespaceURI)) //URI not match continue; DOMString nNamespaceURI = node->getNamespaceURI(); DOMString nLocalName = node->getLocalName(); if (namespaceURI == null) { if (nNamespaceURI == null && (localName.equals(nLocalName) || (nLocalName == null && localName.equals(node->getNodeName())))) return i; } else { if (namespaceURI.equals(nNamespaceURI) && localName.equals(nLocalName)) return i; } } return -1; //not found } NodeImpl *NamedNodeMapImpl::getNamedItemNS(const DOMString &namespaceURI, const DOMString &localName) { int i = findNamePoint(namespaceURI, localName); return i < 0 ? null : nodes -> elementAt(i); } // // setNamedItemNS() Put the item into the NamedNodeList by name. // If an item with the same name already was // in the list, replace it. Return the old // item, if there was one. // Caller is responsible for arranging for // deletion of the old item if its ref count is // zero. // NodeImpl * NamedNodeMapImpl::setNamedItemNS(NodeImpl *arg) { if (arg->getOwnerDocument() != ownerNode->getOwnerDocument()) throw DOM_DOMException(DOM_DOMException::WRONG_DOCUMENT_ERR,null); if (readOnly) throw DOM_DOMException(DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null); if (arg->isOwned()) throw DOM_DOMException(DOM_DOMException::INUSE_ATTRIBUTE_ERR,null); arg->ownerNode = ownerNode; arg->isOwned(true); int i=findNamePoint(arg->getNamespaceURI(), arg->getLocalName()); NodeImpl *previous=null; if(i>=0) { previous = nodes->elementAt(i); nodes->setElementAt(arg,i); } else { i=findNamePoint(arg->getNodeName()); // Insert point (may be end of list) if (i<0) i = -1 - i; if(null==nodes) { MemoryManager* manager = ownerNode->getDocument()->getMemoryManager(); nodes=new (manager) NodeVector(manager); } nodes->insertElementAt(arg,i); } if (previous != null) { previous->ownerNode = ownerNode->getOwnerDocument(); previous->isOwned(false); } return previous; }; // removeNamedItemNS() - Remove the named item, and return it. // The caller must arrange for deletion of the // returned item if its refcount has gone to zero - // we can't do it here because the caller would // never see the returned node. NodeImpl *NamedNodeMapImpl::removeNamedItemNS(const DOMString &namespaceURI, const DOMString &localName) { if (readOnly) throw DOM_DOMException( DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null); int i = findNamePoint(namespaceURI, localName); if (i < 0) throw DOM_DOMException(DOM_DOMException::NOT_FOUND_ERR, null); NodeImpl * n = nodes -> elementAt(i); nodes -> removeElementAt(i); //remove n from nodes n->ownerNode = ownerNode->getOwnerDocument(); n->isOwned(false); return n; } /** * NON-DOM * set the ownerDocument of this node, its children, and its attributes */ void NamedNodeMapImpl::setOwnerDocument(DocumentImpl *doc) { if (nodes != null) { for (unsigned int i = 0; i < nodes->size(); i++) { item(i)->setOwnerDocument(doc); } } } void NamedNodeMapImpl::cloneContent(NamedNodeMapImpl *srcmap) { if ((srcmap != null) && (srcmap->nodes != null) && (srcmap->nodes->size() > 0)) { if (nodes != null) { delete nodes; } MemoryManager* manager = ownerNode->getDocument()->getMemoryManager(); nodes = new (manager) NodeVector(srcmap->nodes->size(), manager); for (unsigned int i = 0; i < srcmap->nodes->size(); i++) { NodeImpl *n = srcmap->nodes->elementAt(i); NodeImpl *clone = n->cloneNode(true); clone->isSpecified(n->isSpecified()); clone->ownerNode = ownerNode; clone->isOwned(true); nodes->addElement(clone); // n = null; // clone = null; } } } XERCES_CPP_NAMESPACE_END