GME  13
DOMParentNode.cpp
Go to the documentation of this file.
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