GME
13
|
00001 /* 00002 * Licensed to the Apache Software Foundation (ASF) under one or more 00003 * contributor license agreements. See the NOTICE file distributed with 00004 * this work for additional information regarding copyright ownership. 00005 * The ASF licenses this file to You under the Apache License, Version 2.0 00006 * (the "License"); you may not use this file except in compliance with 00007 * the License. You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 /* 00019 * $Id: DOMParentNode.cpp 678709 2008-07-22 10:56:56Z borisk $ 00020 */ 00021 00022 #include <xercesc/util/XercesDefs.hpp> 00023 #include <xercesc/dom/DOMException.hpp> 00024 #include <xercesc/dom/DOMNode.hpp> 00025 00026 #include "DOMDocumentImpl.hpp" 00027 #include "DOMRangeImpl.hpp" 00028 #include "DOMNodeIteratorImpl.hpp" 00029 #include "DOMParentNode.hpp" 00030 #include "DOMCasts.hpp" 00031 00032 XERCES_CPP_NAMESPACE_BEGIN 00033 00034 DOMParentNode::DOMParentNode(DOMDocument *ownerDoc) 00035 : fOwnerDocument(ownerDoc), fFirstChild(0), fChildNodeList(this) 00036 { 00037 } 00038 00039 // This only makes a shallow copy, cloneChildren must also be called for a 00040 // deep clone 00041 DOMParentNode::DOMParentNode(const DOMParentNode &other) : 00042 fChildNodeList(this) 00043 { 00044 this->fOwnerDocument = other.fOwnerDocument; 00045 00046 // Need to break the association w/ original kids 00047 this->fFirstChild = 0; 00048 } 00049 00050 void DOMParentNode::changed() 00051 { 00052 ((DOMDocumentImpl*)fOwnerDocument)->changed(); 00053 } 00054 00055 00056 int DOMParentNode::changes() const 00057 { 00058 return ((DOMDocumentImpl*)fOwnerDocument)->changes(); 00059 } 00060 00061 00062 DOMNode * DOMParentNode::appendChild(DOMNode *newChild) 00063 { 00064 return insertBefore(newChild, 0); 00065 } 00066 00067 00068 void DOMParentNode::cloneChildren(const DOMNode *other) { 00069 // for (DOMNode *mykid = other.getFirstChild(); 00070 for (DOMNode *mykid = other->getFirstChild(); 00071 mykid != 0; 00072 mykid = mykid->getNextSibling()) 00073 { 00074 appendChild(mykid->cloneNode(true)); 00075 } 00076 } 00077 00078 DOMDocument * DOMParentNode::getOwnerDocument() const { 00079 return fOwnerDocument; 00080 } 00081 00082 // unlike getOwnerDocument this is not overriden by DocumentImpl to return 0 00083 DOMDocument * DOMParentNode::getDocument() const { 00084 return fOwnerDocument; 00085 } 00086 00087 void DOMParentNode::setOwnerDocument(DOMDocument* doc) { 00088 fOwnerDocument = doc; 00089 } 00090 00091 DOMNodeList *DOMParentNode::getChildNodes() const { 00092 const DOMNodeList *ret = &fChildNodeList; 00093 return (DOMNodeList *)ret; // cast off const. 00094 } 00095 00096 00097 DOMNode * DOMParentNode::getFirstChild() const { 00098 return fFirstChild; 00099 } 00100 00101 00102 DOMNode * DOMParentNode::getLastChild() const 00103 { 00104 return lastChild(); 00105 } 00106 00107 DOMNode * DOMParentNode::lastChild() const 00108 { 00109 // last child is stored as the previous sibling of first child 00110 if (fFirstChild == 0) { 00111 return 0; 00112 } 00113 00114 DOMChildNode *firstChild = castToChildImpl(fFirstChild); 00115 DOMNode *ret = firstChild->previousSibling; 00116 return ret; 00117 } 00118 00119 00120 // 00121 // revisit. Is this function used anywhere? I don't see it. 00122 // 00123 void DOMParentNode::lastChild(DOMNode *node) { 00124 // store lastChild as previous sibling of first child 00125 if (fFirstChild != 0) { 00126 DOMChildNode *firstChild = castToChildImpl(fFirstChild); 00127 firstChild->previousSibling = node; 00128 } 00129 } 00130 00131 00132 bool DOMParentNode::hasChildNodes() const 00133 { 00134 return fFirstChild!=0; 00135 } 00136 00137 00138 00139 DOMNode *DOMParentNode::insertBefore(DOMNode *newChild, DOMNode *refChild) { 00140 //not really in the specs, but better than nothing 00141 if(newChild==NULL) 00142 throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, GetDOMParentNodeMemoryManager); 00143 00144 DOMNodeImpl *thisNodeImpl = castToNodeImpl(this); 00145 if (thisNodeImpl->isReadOnly()) 00146 throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMParentNodeMemoryManager); 00147 00148 if (newChild->getOwnerDocument() != fOwnerDocument) 00149 throw DOMException(DOMException::WRONG_DOCUMENT_ERR, 0, GetDOMParentNodeMemoryManager); 00150 00151 // Prevent cycles in the tree 00152 //only need to do this if the node has children 00153 if(newChild->hasChildNodes()) { 00154 bool treeSafe=true; 00155 for(DOMNode *a=castToNode(this)->getParentNode(); 00156 treeSafe && a!=0; 00157 a=a->getParentNode()) 00158 treeSafe=(newChild!=a); 00159 if(!treeSafe) 00160 throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, GetDOMParentNodeMemoryManager); 00161 } 00162 00163 // refChild must in fact be a child of this node (or 0) 00164 if (refChild!=0 && refChild->getParentNode() != castToNode(this)) 00165 throw DOMException(DOMException::NOT_FOUND_ERR,0, GetDOMParentNodeMemoryManager); 00166 00167 // if the new node has to be placed before itself, we don't have to do anything 00168 // (even worse, we would crash if we continue, as we assume they are two distinct nodes) 00169 if (refChild!=0 && newChild->isSameNode(refChild)) 00170 return newChild; 00171 00172 if (newChild->getNodeType() == DOMNode::DOCUMENT_FRAGMENT_NODE) 00173 { 00174 // SLOW BUT SAFE: We could insert the whole subtree without 00175 // juggling so many next/previous pointers. (Wipe out the 00176 // parent's child-list, patch the parent pointers, set the 00177 // ends of the list.) But we know some subclasses have special- 00178 // case behavior they add to insertBefore(), so we don't risk it. 00179 // This approch also takes fewer bytecodes. 00180 00181 // NOTE: If one of the children is not a legal child of this 00182 // node, throw HIERARCHY_REQUEST_ERR before _any_ of the children 00183 // have been transferred. (Alternative behaviors would be to 00184 // reparent up to the first failure point or reparent all those 00185 // which are acceptable to the target node, neither of which is 00186 // as robust. PR-DOM-0818 isn't entirely clear on which it 00187 // recommends????? 00188 00189 // No need to check kids for right-document; if they weren't, 00190 // they wouldn't be kids of that DocFrag. 00191 for(DOMNode *kid=newChild->getFirstChild(); // Prescan 00192 kid!=0; 00193 kid=kid->getNextSibling()) 00194 { 00195 if (!DOMDocumentImpl::isKidOK(castToNode(this), kid)) 00196 throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, GetDOMParentNodeMemoryManager); 00197 } 00198 while(newChild->hasChildNodes()) // Move 00199 castToNode(this)->insertBefore(newChild->getFirstChild(),refChild); 00200 } 00201 00202 else if (!DOMDocumentImpl::isKidOK(castToNode(this), newChild)) 00203 throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, GetDOMParentNodeMemoryManager); 00204 00205 else 00206 { 00207 DOMNode *oldparent=newChild->getParentNode(); 00208 if(oldparent!=0) 00209 oldparent->removeChild(newChild); 00210 00211 // Attach up 00212 castToNodeImpl(newChild)->fOwnerNode = castToNode(this); 00213 castToNodeImpl(newChild)->isOwned(true); 00214 00215 // Attach before and after 00216 // Note: fFirstChild.previousSibling == lastChild!! 00217 if (fFirstChild == 0) { 00218 // this our first and only child 00219 fFirstChild = newChild; 00220 castToNodeImpl(newChild)->isFirstChild(true); 00221 // castToChildImpl(newChild)->previousSibling = newChild; 00222 DOMChildNode *newChild_ci = castToChildImpl(newChild); 00223 newChild_ci->previousSibling = newChild; 00224 } else { 00225 if (refChild == 0) { 00226 // this is an append 00227 DOMNode *lastChild = castToChildImpl(fFirstChild)->previousSibling; 00228 castToChildImpl(lastChild)->nextSibling = newChild; 00229 castToChildImpl(newChild)->previousSibling = lastChild; 00230 castToChildImpl(fFirstChild)->previousSibling = newChild; 00231 } else { 00232 // this is an insert 00233 if (refChild == fFirstChild) { 00234 // at the head of the list 00235 castToNodeImpl(fFirstChild)->isFirstChild(false); 00236 castToChildImpl(newChild)->nextSibling = fFirstChild; 00237 castToChildImpl(newChild)->previousSibling = castToChildImpl(fFirstChild)->previousSibling; 00238 castToChildImpl(fFirstChild)->previousSibling = newChild; 00239 fFirstChild = newChild; 00240 castToNodeImpl(newChild)->isFirstChild(true); 00241 } else { 00242 // somewhere in the middle 00243 DOMNode *prev = castToChildImpl(refChild)->previousSibling; 00244 castToChildImpl(newChild)->nextSibling = refChild; 00245 castToChildImpl(prev)->nextSibling = newChild; 00246 castToChildImpl(refChild)->previousSibling = newChild; 00247 castToChildImpl(newChild)->previousSibling = prev; 00248 } 00249 } 00250 } 00251 } 00252 00253 changed(); 00254 00255 if (fOwnerDocument != 0) { 00256 Ranges* ranges = ((DOMDocumentImpl*)fOwnerDocument)->getRanges(); 00257 if ( ranges != 0) { 00258 XMLSize_t sz = ranges->size(); 00259 if (sz != 0) { 00260 for (XMLSize_t i =0; i<sz; i++) { 00261 ranges->elementAt(i)->updateRangeForInsertedNode(newChild); 00262 } 00263 } 00264 } 00265 } 00266 00267 return newChild; 00268 } 00269 00270 00271 00272 DOMNode *DOMParentNode::removeChild(DOMNode *oldChild) 00273 { 00274 if (castToNodeImpl(this)->isReadOnly()) 00275 throw DOMException( 00276 DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMParentNodeMemoryManager); 00277 00278 if (oldChild == 0 || oldChild->getParentNode() != castToNode(this)) 00279 throw DOMException(DOMException::NOT_FOUND_ERR, 0, GetDOMParentNodeMemoryManager); 00280 00281 if (fOwnerDocument != 0) { 00282 //notify iterators 00283 NodeIterators* nodeIterators = ((DOMDocumentImpl*)fOwnerDocument)->getNodeIterators(); 00284 if (nodeIterators != 0) { 00285 XMLSize_t sz = nodeIterators->size(); 00286 if (sz != 0) { 00287 for (XMLSize_t i =0; i<sz; i++) { 00288 if (nodeIterators->elementAt(i) != 0) 00289 nodeIterators->elementAt(i)->removeNode(oldChild); 00290 } 00291 } 00292 } 00293 00294 //fix other ranges for change before deleting the node 00295 Ranges* ranges = ((DOMDocumentImpl*)fOwnerDocument)->getRanges(); 00296 if (ranges != 0) { 00297 XMLSize_t sz = ranges->size(); 00298 if (sz != 0) { 00299 for (XMLSize_t i =0; i<sz; i++) { 00300 if (ranges->elementAt(i) != 0) 00301 ranges->elementAt(i)->updateRangeForDeletedNode(oldChild); 00302 } 00303 } 00304 } 00305 } 00306 00307 00308 // Patch linked list around oldChild 00309 // Note: lastChild == fFirstChild->previousSibling 00310 if (oldChild == fFirstChild) { 00311 // removing first child 00312 castToNodeImpl(oldChild)->isFirstChild(false); 00313 fFirstChild = castToChildImpl(oldChild)->nextSibling; 00314 if (fFirstChild != 0) { 00315 castToNodeImpl(fFirstChild)->isFirstChild(true); 00316 castToChildImpl(fFirstChild)->previousSibling = castToChildImpl(oldChild)->previousSibling; 00317 } 00318 } else { 00319 DOMNode *prev = castToChildImpl(oldChild)->previousSibling; 00320 DOMNode *next = castToChildImpl(oldChild)->nextSibling; 00321 castToChildImpl(prev)->nextSibling = next; 00322 if (next == 0) { 00323 // removing last child 00324 castToChildImpl(fFirstChild)->previousSibling = prev; 00325 } else { 00326 // removing some other child in the middle 00327 castToChildImpl(next)->previousSibling = prev; 00328 } 00329 } 00330 00331 // Remove oldChild's references to tree 00332 castToNodeImpl(oldChild)->fOwnerNode = fOwnerDocument; 00333 castToNodeImpl(oldChild)->isOwned(false); 00334 castToChildImpl(oldChild)->nextSibling = 0; 00335 castToChildImpl(oldChild)->previousSibling = 0; 00336 00337 changed(); 00338 00339 return oldChild; 00340 } 00341 00342 00343 DOMNode *DOMParentNode::replaceChild(DOMNode *newChild, DOMNode *oldChild) 00344 { 00345 insertBefore(newChild, oldChild); 00346 // changed() already done. 00347 return removeChild(oldChild); 00348 } 00349 00350 00351 DOMNode * DOMParentNode::appendChildFast(DOMNode *newChild) 00352 { 00353 // This function makes the following assumptions: 00354 // 00355 // - newChild != 0 00356 // - newChild is not read-only 00357 // - newChild is not a document fragment 00358 // - owner documents of this node and newChild are the same 00359 // - appending newChild to this node cannot result in a cycle 00360 // - DOMDocumentImpl::isKidOK (this, newChild) return true (that is, 00361 // appending newChild to this node results in a valid structure) 00362 // - newChild->getParentNode() is 0 00363 // - there are no ranges set for this document 00364 // 00365 00366 // Attach up 00367 castToNodeImpl(newChild)->fOwnerNode = castToNode(this); 00368 castToNodeImpl(newChild)->isOwned(true); 00369 00370 // Attach before and after 00371 // Note: fFirstChild.previousSibling == lastChild!! 00372 if (fFirstChild != 0) 00373 { 00374 DOMNode *lastChild = castToChildImpl(fFirstChild)->previousSibling; 00375 castToChildImpl(lastChild)->nextSibling = newChild; 00376 castToChildImpl(newChild)->previousSibling = lastChild; 00377 castToChildImpl(fFirstChild)->previousSibling = newChild; 00378 } 00379 else 00380 { 00381 // this our first and only child 00382 fFirstChild = newChild; 00383 castToNodeImpl(newChild)->isFirstChild(true); 00384 // castToChildImpl(newChild)->previousSibling = newChild; 00385 DOMChildNode *newChild_ci = castToChildImpl(newChild); 00386 newChild_ci->previousSibling = newChild; 00387 } 00388 00389 return newChild; 00390 } 00391 00392 00393 //Introduced in DOM Level 2 00394 00395 void DOMParentNode::normalize() 00396 { 00397 DOMNode *kid, *next; 00398 for (kid = fFirstChild; kid != 0; kid = next) 00399 { 00400 next = castToChildImpl(kid)->nextSibling; 00401 00402 // If kid and next are both Text nodes (but _not_ CDATASection, 00403 // which is a subclass of Text), they can be merged. 00404 if (next != 0 && 00405 kid->getNodeType() == DOMNode::TEXT_NODE && 00406 next->getNodeType() == DOMNode::TEXT_NODE ) 00407 { 00408 ((DOMTextImpl *) kid)->appendData(((DOMTextImpl *) next)->getData()); 00409 // revisit: 00410 // should I release the removed node? 00411 // not released in case user still referencing it externally 00412 removeChild(next); 00413 next = kid; // Don't advance; there might be another. 00414 } 00415 00416 // Otherwise it might be an Element, which is handled recursively 00417 else 00418 if (kid->getNodeType() == DOMNode::ELEMENT_NODE) 00419 kid->normalize(); 00420 } 00421 00422 // changed() will have occurred when the removeChild() was done, 00423 // so does not have to be reissued. 00424 } 00425 00426 //Introduced in DOM Level 3 00427 00428 bool DOMParentNode::isEqualNode(const DOMNode* arg) const 00429 { 00430 if (arg && castToNodeImpl(this)->isSameNode(arg)) 00431 return true; 00432 00433 if (arg && castToNodeImpl(this)->isEqualNode(arg)) 00434 { 00435 DOMNode *kid, *argKid; 00436 for (kid = fFirstChild, argKid = arg->getFirstChild(); 00437 kid != 0 && argKid != 0; 00438 kid = kid->getNextSibling(), argKid = argKid->getNextSibling()) 00439 { 00440 if (!kid->isEqualNode(argKid)) 00441 return false; 00442 } 00443 return (kid || argKid) ? false : true; 00444 } 00445 return false; 00446 } 00447 00448 00449 //Non-standard extension 00450 void DOMParentNode::release() 00451 { 00452 DOMNode *kid, *next; 00453 for (kid = fFirstChild; kid != 0; kid = next) 00454 { 00455 next = castToChildImpl(kid)->nextSibling; 00456 00457 // set is Owned false before releasing its child 00458 castToNodeImpl(kid)->isToBeReleased(true); 00459 kid->release(); 00460 } 00461 } 00462 00463 00464 XERCES_CPP_NAMESPACE_END