Newer
Older
/*
* 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$
*/
#include "DOMAttrMapImpl.hpp"
#include "DOMNodeImpl.hpp"
#include "DOMElementImpl.hpp"
#include "DOMCasts.hpp"
Alberto Massari
committed
#include "DOMNodeVector.hpp"
#include <xercesc/dom/DOMAttr.hpp>
#include <xercesc/dom/DOMException.hpp>
DOMAttrMapImpl::DOMAttrMapImpl(DOMNode *ownerNod)
{
Alberto Massari
committed
this->fOwnerNode=ownerNod;
this->fNodes = 0;
hasDefaults(false);
}
Alberto Massari
committed
DOMAttrMapImpl::DOMAttrMapImpl(DOMNode *ownerNod, const DOMAttrMapImpl *defaults)
{
Alberto Massari
committed
this->fOwnerNode=ownerNod;
this->fNodes = 0;
hasDefaults(false);
if (defaults != 0)
{
if (defaults->getLength() > 0)
{
hasDefaults(true);
cloneContent(defaults);
}
}
}
DOMAttrMapImpl::~DOMAttrMapImpl()
{
}
Alberto Massari
committed
void DOMAttrMapImpl::cloneContent(const DOMAttrMapImpl *srcmap)
{
if ((srcmap != 0) && (srcmap->fNodes != 0))
{
if (fNodes != 0)
fNodes->reset();
else
{
Alberto Massari
committed
unsigned int size = srcmap->fNodes->size();
Alberto Massari
committed
if(size > 0) {
DOMDocument *doc = fOwnerNode->getOwnerDocument();
fNodes = new (doc) DOMNodeVector(doc, size);
}
}
Alberto Massari
committed
for (unsigned int i = 0; i < srcmap->fNodes->size(); i++)
Alberto Massari
committed
{
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;
}
Alberto Massari
committed
void DOMAttrMapImpl::setReadOnly(bool readOnl, bool deep)
{
// this->fReadOnly=readOnl;
if(deep && fNodes!=0)
{
Alberto Massari
committed
unsigned int sz = fNodes->size();
for (unsigned int i=0; i<sz; ++i) {
Alberto Massari
committed
castToNodeImpl(fNodes->elementAt(i))->setReadOnly(readOnl, deep);
}
}
}
bool DOMAttrMapImpl::readOnly() {
return castToNodeImpl(fOwnerNode)->isReadOnly();
}
int DOMAttrMapImpl::findNamePoint(const XMLCh *name) const
{
// Binary search
Alberto Massari
committed
unsigned int i=0;
Alberto Massari
committed
if(fNodes!=0)
{
Alberto Massari
committed
unsigned int first=0,last=fNodes->size()-1;
Alberto Massari
committed
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
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);
Alberto Massari
committed
DOMDocument *doc = fOwnerNode->getOwnerDocument();
DOMNodeImpl *argImpl = castToNodeImpl(arg);
if(argImpl->getOwnerDocument() != doc)
throw DOMException(DOMException::WRONG_DOCUMENT_ERR, 0, GetDOMNamedNodeMapMemoryManager);
Alberto Massari
committed
if (this->readOnly())
throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNamedNodeMapMemoryManager);
Alberto Massari
committed
if ((arg->getNodeType() == DOMNode::ATTRIBUTE_NODE) && argImpl->isOwned() && (argImpl->fOwnerNode != fOwnerNode))
throw DOMException(DOMException::INUSE_ATTRIBUTE_ERR,0, GetDOMNamedNodeMapMemoryManager);
Alberto Massari
committed
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
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.
Alberto Massari
committed
unsigned int i, len = fNodes -> size();
Alberto Massari
committed
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);
Alberto Massari
committed
DOMDocument *doc = fOwnerNode->getOwnerDocument();
DOMNodeImpl *argImpl = castToNodeImpl(arg);
if (argImpl->getOwnerDocument() != doc)
throw DOMException(DOMException::WRONG_DOCUMENT_ERR,0, GetDOMNamedNodeMapMemoryManager);
Alberto Massari
committed
if (this->readOnly())
throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNamedNodeMapMemoryManager);
Alberto Massari
committed
if (argImpl->isOwned())
throw DOMException(DOMException::INUSE_ATTRIBUTE_ERR,0, GetDOMNamedNodeMapMemoryManager);
Alberto Massari
committed
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)
{
Alberto Massari
committed
if (this->readOnly())
throw DOMException(
DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNamedNodeMapMemoryManager);
Alberto Massari
committed
int i=findNamePoint(name);
DOMNode *removed = 0;
if(i<0)
throw DOMException(DOMException::NOT_FOUND_ERR, 0, GetDOMNamedNodeMapMemoryManager);
Alberto Massari
committed
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);
}
}
}
DOMNode *DOMAttrMapImpl::removeNamedItemNS(const XMLCh *namespaceURI, const XMLCh *localName)
{
Alberto Massari
committed
if (this->readOnly())
throw DOMException(
DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNamedNodeMapMemoryManager);
Alberto Massari
committed
int i = findNamePoint(namespaceURI, localName);
if (i < 0)
throw DOMException(DOMException::NOT_FOUND_ERR, 0, GetDOMNamedNodeMapMemoryManager);
Alberto Massari
committed
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);
}
}
}
// remove the name using index
// avoid calling findNamePoint again if the index is already known
Alberto Massari
committed
DOMNode * DOMAttrMapImpl::removeNamedItemAt(unsigned int index)
Alberto Massari
committed
if (this->readOnly())
throw DOMException(
DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNamedNodeMapMemoryManager);
Alberto Massari
committed
DOMNode *removed = item(index);
if(!removed)
throw DOMException(DOMException::NOT_FOUND_ERR, 0, GetDOMNamedNodeMapMemoryManager);
Alberto Massari
committed
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
Alberto Massari
committed
unsigned int nsize = getLength();
for (unsigned int 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 {
Alberto Massari
committed
unsigned int dsize = defaults->getLength();
for (unsigned int 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) {
Alberto Massari
committed
unsigned int nsize = srcmap->getLength();
Alberto Massari
committed
for (unsigned int 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
Alberto Massari
committed
unsigned int DOMAttrMapImpl::getLength() const
Alberto Massari
committed
{
return (fNodes != 0) ? fNodes->size() : 0;
}
Alberto Massari
committed
DOMNode * DOMAttrMapImpl::item(unsigned int index) const
Alberto Massari
committed
{
return (fNodes != 0 && index < fNodes->size()) ?
fNodes->elementAt(index) : 0;
}