| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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: DOMAttrMapImpl.cpp 568078 2007-08-21 11:43:25Z amassari $ |
| */ |
| |
| #include "DOMAttrMapImpl.hpp" |
| #include "DOMAttrImpl.hpp" |
| #include "DOMNodeImpl.hpp" |
| #include "DOMElementImpl.hpp" |
| #include "DOMCasts.hpp" |
| #include "DOMNodeVector.hpp" |
| |
| #include <xercesc/dom/DOMAttr.hpp> |
| #include <xercesc/dom/DOMException.hpp> |
| |
| XERCES_CPP_NAMESPACE_BEGIN |
| |
| DOMAttrMapImpl::DOMAttrMapImpl(DOMNode *ownerNod) |
| { |
| this->fOwnerNode=ownerNod; |
| this->fNodes = 0; |
| hasDefaults(false); |
| } |
| |
| DOMAttrMapImpl::DOMAttrMapImpl(DOMNode *ownerNod, const DOMAttrMapImpl *defaults) |
| { |
| this->fOwnerNode=ownerNod; |
| this->fNodes = 0; |
| hasDefaults(false); |
| if (defaults != 0) |
| { |
| if (defaults->getLength() > 0) |
| { |
| hasDefaults(true); |
| cloneContent(defaults); |
| } |
| } |
| } |
| |
| DOMAttrMapImpl::~DOMAttrMapImpl() |
| { |
| } |
| |
| void DOMAttrMapImpl::cloneContent(const DOMAttrMapImpl *srcmap) |
| { |
| if ((srcmap != 0) && (srcmap->fNodes != 0)) |
| { |
| if (fNodes != 0) |
| fNodes->reset(); |
| else |
| { |
| XMLSize_t size = srcmap->fNodes->size(); |
| if(size > 0) { |
| DOMDocument *doc = fOwnerNode->getOwnerDocument(); |
| fNodes = new (doc) DOMNodeVector(doc, size); |
| } |
| } |
| |
| for (XMLSize_t i = 0; i < srcmap->fNodes->size(); i++) |
| { |
| DOMNode *n = srcmap->fNodes->elementAt(i); |
| DOMNode *clone = n->cloneNode(true); |
| castToNodeImpl(clone)->isSpecified(castToNodeImpl(n)->isSpecified()); |
| castToNodeImpl(clone)->fOwnerNode = fOwnerNode; |
| castToNodeImpl(clone)->isOwned(true); |
| fNodes->addElement(clone); |
| } |
| } |
| } |
| |
| DOMAttrMapImpl *DOMAttrMapImpl::cloneAttrMap(DOMNode *ownerNode_p) |
| { |
| DOMAttrMapImpl *newmap = new (castToNodeImpl(ownerNode_p)->getOwnerDocument()) DOMAttrMapImpl(ownerNode_p); |
| newmap->cloneContent(this); |
| // newmap->attrDefaults = this->attrDefaults; // revisit |
| return newmap; |
| } |
| |
| void DOMAttrMapImpl::setReadOnly(bool readOnl, bool deep) |
| { |
| // this->fReadOnly=readOnl; |
| if(deep && fNodes!=0) |
| { |
| int sz = fNodes->size(); |
| for (int i=0; i<sz; ++i) { |
| castToNodeImpl(fNodes->elementAt(i))->setReadOnly(readOnl, deep); |
| } |
| } |
| } |
| |
| bool DOMAttrMapImpl::readOnly() { |
| return castToNodeImpl(fOwnerNode)->isReadOnly(); |
| } |
| |
| int DOMAttrMapImpl::findNamePoint(const XMLCh *name) const |
| { |
| |
| // Binary search |
| int i=0; |
| if(fNodes!=0) |
| { |
| int first=0,last=fNodes->size()-1; |
| |
| while(first<=last) |
| { |
| i=(first+last)/2; |
| int test = XMLString::compareString(name, fNodes->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 (fNodes != 0) |
| for (i = 0; i < fNodes.size(); ++i) |
| { |
| int test = name.compareTo(((NodeImpl *) (fNodes.elementAt(i))).getNodeName()); |
| if (test == 0) |
| return i; |
| else |
| if (test < 0) |
| { |
| break; // Found insertpoint |
| } |
| } |
| |
| *******************/ |
| return -1 - i; // not-found has to be encoded. |
| } |
| |
| DOMNode * DOMAttrMapImpl::getNamedItem(const XMLCh *name) const |
| { |
| int i=findNamePoint(name); |
| return (i<0) ? 0 : fNodes->elementAt(i); |
| } |
| |
| DOMNode *DOMAttrMapImpl::setNamedItem(DOMNode *arg) |
| { |
| if (arg->getNodeType() != DOMNode::ATTRIBUTE_NODE) |
| throw DOMException(DOMException::HIERARCHY_REQUEST_ERR, 0, GetDOMNamedNodeMapMemoryManager); |
| |
| DOMDocument *doc = fOwnerNode->getOwnerDocument(); |
| DOMNodeImpl *argImpl = castToNodeImpl(arg); |
| if(argImpl->getOwnerDocument() != doc) |
| throw DOMException(DOMException::WRONG_DOCUMENT_ERR, 0, GetDOMNamedNodeMapMemoryManager); |
| if (this->readOnly()) |
| throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNamedNodeMapMemoryManager); |
| if ((arg->getNodeType() == DOMNode::ATTRIBUTE_NODE) && argImpl->isOwned() && (argImpl->fOwnerNode != fOwnerNode)) |
| throw DOMException(DOMException::INUSE_ATTRIBUTE_ERR,0, GetDOMNamedNodeMapMemoryManager); |
| |
| argImpl->fOwnerNode = fOwnerNode; |
| argImpl->isOwned(true); |
| int i=findNamePoint(arg->getNodeName()); |
| DOMNode * previous=0; |
| if(i>=0) |
| { |
| previous = fNodes->elementAt(i); |
| fNodes->setElementAt(arg,i); |
| } |
| else |
| { |
| i=-1-i; // Insert point (may be end of list) |
| if(0==fNodes) |
| { |
| fNodes=new (doc) DOMNodeVector(doc); |
| } |
| fNodes->insertElementAt(arg,i); |
| } |
| if (previous != 0) { |
| castToNodeImpl(previous)->fOwnerNode = fOwnerNode->getOwnerDocument(); |
| castToNodeImpl(previous)->isOwned(false); |
| } |
| |
| return previous; |
| } |
| |
| //Introduced in DOM Level 2 |
| |
| int DOMAttrMapImpl::findNamePoint(const XMLCh *namespaceURI, |
| const XMLCh *localName) const |
| { |
| if (fNodes == 0) |
| return -1; |
| // This is a linear search through the same fNodes 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 fNodes without any namespace |
| // (namespaceURI and localNames are both 0) we then use the nodeName |
| // as a secondary key. |
| int i, len = fNodes -> size(); |
| for (i = 0; i < len; ++i) { |
| DOMNode *node = fNodes -> elementAt(i); |
| const XMLCh * nNamespaceURI = node->getNamespaceURI(); |
| const XMLCh * nLocalName = node->getLocalName(); |
| if (!XMLString::equals(nNamespaceURI, namespaceURI)) //URI not match |
| continue; |
| else { |
| if (XMLString::equals(localName, nLocalName) |
| || |
| (nLocalName == 0 && XMLString::equals(localName, node->getNodeName()))) |
| return i; |
| } |
| } |
| return -1; //not found |
| } |
| |
| DOMNode *DOMAttrMapImpl::getNamedItemNS(const XMLCh *namespaceURI, |
| const XMLCh *localName) const |
| { |
| int i = findNamePoint(namespaceURI, localName); |
| return i < 0 ? 0 : fNodes -> elementAt(i); |
| } |
| |
| DOMNode *DOMAttrMapImpl::setNamedItemNS(DOMNode* arg) |
| { |
| if (arg->getNodeType() != DOMNode::ATTRIBUTE_NODE) |
| throw DOMException(DOMException::HIERARCHY_REQUEST_ERR, 0, GetDOMNamedNodeMapMemoryManager); |
| |
| DOMDocument *doc = fOwnerNode->getOwnerDocument(); |
| DOMNodeImpl *argImpl = castToNodeImpl(arg); |
| if (argImpl->getOwnerDocument() != doc) |
| throw DOMException(DOMException::WRONG_DOCUMENT_ERR,0, GetDOMNamedNodeMapMemoryManager); |
| if (this->readOnly()) |
| throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNamedNodeMapMemoryManager); |
| if (argImpl->isOwned()) |
| throw DOMException(DOMException::INUSE_ATTRIBUTE_ERR,0, GetDOMNamedNodeMapMemoryManager); |
| |
| argImpl->fOwnerNode = fOwnerNode; |
| argImpl->isOwned(true); |
| int i=findNamePoint(arg->getNamespaceURI(), arg->getLocalName()); |
| DOMNode *previous=0; |
| if(i>=0) { |
| previous = fNodes->elementAt(i); |
| fNodes->setElementAt(arg,i); |
| } else { |
| i=findNamePoint(arg->getNodeName()); // Insert point (may be end of list) |
| if (i<0) |
| i = -1 - i; |
| if(0==fNodes) |
| fNodes=new (doc) DOMNodeVector(doc); |
| fNodes->insertElementAt(arg,i); |
| } |
| if (previous != 0) { |
| castToNodeImpl(previous)->fOwnerNode = fOwnerNode->getOwnerDocument(); |
| castToNodeImpl(previous)->isOwned(false); |
| } |
| |
| return previous; |
| } |
| |
| DOMNode *DOMAttrMapImpl::removeNamedItem(const XMLCh *name) |
| { |
| if (this->readOnly()) |
| throw DOMException( |
| DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNamedNodeMapMemoryManager); |
| int i=findNamePoint(name); |
| DOMNode *removed = 0; |
| |
| if(i<0) |
| throw DOMException(DOMException::NOT_FOUND_ERR, 0, GetDOMNamedNodeMapMemoryManager); |
| |
| removed = fNodes->elementAt(i); |
| fNodes->removeElementAt(i); |
| castToNodeImpl(removed)->fOwnerNode = fOwnerNode->getOwnerDocument(); |
| castToNodeImpl(removed)->isOwned(false); |
| |
| // Replace it if it had a default value |
| // (DOM spec level 1 - Element Interface) |
| if (hasDefaults() && (removed != 0)) |
| { |
| DOMAttrMapImpl* defAttrs = ((DOMElementImpl*)fOwnerNode)->getDefaultAttributes(); |
| DOMAttr* attr = (DOMAttr*)(defAttrs->getNamedItem(name)); |
| if (attr != 0) |
| { |
| DOMAttr* newAttr = (DOMAttr*)attr->cloneNode(true); |
| setNamedItem(newAttr); |
| } |
| } |
| |
| return removed; |
| } |
| |
| DOMNode *DOMAttrMapImpl::removeNamedItemNS(const XMLCh *namespaceURI, const XMLCh *localName) |
| { |
| if (this->readOnly()) |
| throw DOMException( |
| DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNamedNodeMapMemoryManager); |
| int i = findNamePoint(namespaceURI, localName); |
| if (i < 0) |
| throw DOMException(DOMException::NOT_FOUND_ERR, 0, GetDOMNamedNodeMapMemoryManager); |
| |
| DOMNode * removed = fNodes -> elementAt(i); |
| fNodes -> removeElementAt(i); //remove n from nodes |
| castToNodeImpl(removed)->fOwnerNode = fOwnerNode->getOwnerDocument(); |
| castToNodeImpl(removed)->isOwned(false); |
| |
| // Replace it if it had a default value |
| // (DOM spec level 2 - Element Interface) |
| |
| if (hasDefaults() && (removed != 0)) |
| { |
| DOMAttrMapImpl* defAttrs = ((DOMElementImpl*)fOwnerNode)->getDefaultAttributes(); |
| DOMAttr* attr = (DOMAttr*)(defAttrs->getNamedItemNS(namespaceURI, localName)); |
| if (attr != 0) |
| { |
| DOMAttr* newAttr = (DOMAttr*)attr->cloneNode(true); |
| setNamedItemNS(newAttr); |
| } |
| } |
| |
| return removed; |
| } |
| |
| // remove the name using index |
| // avoid calling findNamePoint again if the index is already known |
| DOMNode * DOMAttrMapImpl::removeNamedItemAt(XMLSize_t index) |
| { |
| if (this->readOnly()) |
| throw DOMException( |
| DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNamedNodeMapMemoryManager); |
| |
| DOMNode *removed = item(index); |
| if(!removed) |
| throw DOMException(DOMException::NOT_FOUND_ERR, 0, GetDOMNamedNodeMapMemoryManager); |
| |
| fNodes->removeElementAt(index); |
| castToNodeImpl(removed)->fOwnerNode = fOwnerNode->getOwnerDocument(); |
| castToNodeImpl(removed)->isOwned(false); |
| |
| // Replace it if it had a default value |
| // (DOM spec level 1 - Element Interface) |
| if (hasDefaults() && (removed != 0)) |
| { |
| DOMAttrMapImpl* defAttrs = ((DOMElementImpl*)fOwnerNode)->getDefaultAttributes(); |
| |
| const XMLCh* localName = removed->getLocalName(); |
| DOMAttr* attr = 0; |
| if (localName) |
| attr = (DOMAttr*)(defAttrs->getNamedItemNS(removed->getNamespaceURI(), localName)); |
| else |
| attr = (DOMAttr*)(defAttrs->getNamedItem(((DOMAttr*)removed)->getName())); |
| |
| if (attr != 0) |
| { |
| DOMAttr* newAttr = (DOMAttr*)attr->cloneNode(true); |
| setNamedItem(newAttr); |
| } |
| } |
| |
| return removed; |
| } |
| |
| /** |
| * Get this AttributeMap in sync with the given "defaults" map. |
| * @param defaults The default attributes map to sync with. |
| */ |
| void DOMAttrMapImpl::reconcileDefaultAttributes(const DOMAttrMapImpl* defaults) { |
| |
| // remove any existing default |
| XMLSize_t nsize = getLength(); |
| for (XMLSSize_t i = nsize - 1; i >= 0; i--) { |
| DOMAttr* attr = (DOMAttr*)item(i); |
| if (!attr->getSpecified()) { |
| removeNamedItemAt(i); |
| } |
| } |
| |
| hasDefaults(false); |
| |
| // add the new defaults |
| if (defaults) { |
| hasDefaults(true); |
| |
| if (nsize == 0) { |
| cloneContent(defaults); |
| } |
| else { |
| XMLSize_t dsize = defaults->getLength(); |
| for (XMLSize_t n = 0; n < dsize; n++) { |
| DOMAttr* attr = (DOMAttr*)defaults->item(n); |
| |
| DOMAttr* newAttr = (DOMAttr*)attr->cloneNode(true); |
| setNamedItemNS(newAttr); |
| DOMAttrImpl* newAttrImpl = (DOMAttrImpl*) newAttr; |
| newAttrImpl->setSpecified(false); |
| } |
| } |
| } |
| } // reconcileDefaults() |
| |
| |
| /** |
| * Move specified attributes from the given map to this one |
| */ |
| void DOMAttrMapImpl::moveSpecifiedAttributes(DOMAttrMapImpl* srcmap) { |
| XMLSize_t nsize = srcmap->getLength(); |
| |
| for (XMLSSize_t i = nsize - 1; i >= 0; i--) { |
| DOMAttr* attr = (DOMAttr*)srcmap->item(i); |
| if (attr->getSpecified()) { |
| srcmap->removeNamedItemAt(i); |
| } |
| |
| if (attr->getLocalName()) |
| setNamedItemNS(attr); |
| else |
| setNamedItem(attr); |
| } |
| } // moveSpecifiedAttributes(AttributeMap):void |
| |
| XMLSize_t DOMAttrMapImpl::getLength() const |
| { |
| return (fNodes != 0) ? fNodes->size() : 0; |
| } |
| |
| DOMNode * DOMAttrMapImpl::item(XMLSize_t index) const |
| { |
| return (fNodes != 0 && index < fNodes->size()) ? |
| fNodes->elementAt(index) : 0; |
| } |
| |
| |
| XERCES_CPP_NAMESPACE_END |
| |