source: icXML/icXML-devel/src/xercesc/dom/impl/DOMParentNode.cpp @ 2722

Last change on this file since 2722 was 2722, checked in by cameron, 6 years ago

Original Xerces files with import mods for icxercesc

File size: 15.3 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/*
19 * $Id: DOMParentNode.cpp 678709 2008-07-22 10:56:56Z borisk $
20 */
21
22#include <xercesc/util/XercesDefs.hpp>
23#include <xercesc/dom/DOMException.hpp>
24#include <xercesc/dom/DOMNode.hpp>
25
26#include "DOMDocumentImpl.hpp"
27#include "DOMRangeImpl.hpp"
28#include "DOMNodeIteratorImpl.hpp"
29#include "DOMParentNode.hpp"
30#include "DOMCasts.hpp"
31
32XERCES_CPP_NAMESPACE_BEGIN
33
34DOMParentNode::DOMParentNode(DOMDocument *ownerDoc)
35    : fOwnerDocument(ownerDoc), fFirstChild(0), fChildNodeList(this)
36{
37}
38
39// This only makes a shallow copy, cloneChildren must also be called for a
40// deep clone
41DOMParentNode::DOMParentNode(const DOMParentNode &other)  :
42    fChildNodeList(this)
43{
44    this->fOwnerDocument = other.fOwnerDocument;
45
46    // Need to break the association w/ original kids
47    this->fFirstChild = 0;
48}
49
50void DOMParentNode::changed()
51{
52  ((DOMDocumentImpl*)fOwnerDocument)->changed();
53}
54
55
56int DOMParentNode::changes() const
57{
58    return ((DOMDocumentImpl*)fOwnerDocument)->changes();
59}
60
61
62DOMNode * DOMParentNode::appendChild(DOMNode *newChild)
63{
64    return insertBefore(newChild, 0);
65}
66
67
68void DOMParentNode::cloneChildren(const DOMNode *other) {
69  //    for (DOMNode *mykid = other.getFirstChild();
70    for (DOMNode *mykid = other->getFirstChild();
71         mykid != 0;
72         mykid = mykid->getNextSibling())
73    {
74        appendChild(mykid->cloneNode(true));
75    }
76}
77
78DOMDocument * DOMParentNode::getOwnerDocument() const {
79    return fOwnerDocument;
80}
81
82// unlike getOwnerDocument this is not overriden by DocumentImpl to return 0
83DOMDocument * DOMParentNode::getDocument() const {
84    return fOwnerDocument;
85}
86
87void DOMParentNode::setOwnerDocument(DOMDocument* doc) {
88    fOwnerDocument = doc;
89}
90
91DOMNodeList *DOMParentNode::getChildNodes() const {
92    const DOMNodeList *ret = &fChildNodeList;
93    return (DOMNodeList *)ret;   // cast off const.
94}
95
96
97DOMNode * DOMParentNode::getFirstChild() const {
98    return fFirstChild;
99}
100
101
102DOMNode * DOMParentNode::getLastChild() const
103{
104    return lastChild();
105}
106
107DOMNode * DOMParentNode::lastChild() const
108{
109    // last child is stored as the previous sibling of first child
110    if (fFirstChild == 0) {
111        return 0;
112    }
113
114    DOMChildNode *firstChild = castToChildImpl(fFirstChild);
115    DOMNode *ret = firstChild->previousSibling;
116    return ret;
117}
118
119
120//
121//  revisit.  Is this function used anywhere?  I don't see it.
122//
123void DOMParentNode::lastChild(DOMNode *node) {
124    // store lastChild as previous sibling of first child
125    if (fFirstChild != 0) {
126        DOMChildNode *firstChild = castToChildImpl(fFirstChild);
127        firstChild->previousSibling = node;
128    }
129}
130
131
132bool DOMParentNode::hasChildNodes() const
133{
134    return fFirstChild!=0;
135}
136
137
138
139DOMNode *DOMParentNode::insertBefore(DOMNode *newChild, DOMNode *refChild) {
140    //not really in the specs, but better than nothing
141    if(newChild==NULL)
142        throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, GetDOMParentNodeMemoryManager);
143
144    DOMNodeImpl *thisNodeImpl = castToNodeImpl(this);
145    if (thisNodeImpl->isReadOnly())
146        throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMParentNodeMemoryManager);
147
148    if (newChild->getOwnerDocument() != fOwnerDocument)
149        throw DOMException(DOMException::WRONG_DOCUMENT_ERR, 0, GetDOMParentNodeMemoryManager);
150
151    // Prevent cycles in the tree
152    //only need to do this if the node has children
153    if(newChild->hasChildNodes()) {
154        bool treeSafe=true;
155        for(DOMNode *a=castToNode(this)->getParentNode();
156            treeSafe && a!=0;
157            a=a->getParentNode())
158            treeSafe=(newChild!=a);
159        if(!treeSafe)
160            throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, GetDOMParentNodeMemoryManager);
161    }
162
163    // refChild must in fact be a child of this node (or 0)
164    if (refChild!=0 && refChild->getParentNode() != castToNode(this))
165        throw DOMException(DOMException::NOT_FOUND_ERR,0, GetDOMParentNodeMemoryManager);
166
167    // if the new node has to be placed before itself, we don't have to do anything
168    // (even worse, we would crash if we continue, as we assume they are two distinct nodes)
169    if (refChild!=0 && newChild->isSameNode(refChild))
170        return newChild;
171
172    if (newChild->getNodeType() == DOMNode::DOCUMENT_FRAGMENT_NODE)
173    {
174        // SLOW BUT SAFE: We could insert the whole subtree without
175        // juggling so many next/previous pointers. (Wipe out the
176        // parent's child-list, patch the parent pointers, set the
177        // ends of the list.) But we know some subclasses have special-
178        // case behavior they add to insertBefore(), so we don't risk it.
179        // This approch also takes fewer bytecodes.
180
181        // NOTE: If one of the children is not a legal child of this
182        // node, throw HIERARCHY_REQUEST_ERR before _any_ of the children
183        // have been transferred. (Alternative behaviors would be to
184        // reparent up to the first failure point or reparent all those
185        // which are acceptable to the target node, neither of which is
186        // as robust. PR-DOM-0818 isn't entirely clear on which it
187        // recommends?????
188
189        // No need to check kids for right-document; if they weren't,
190        // they wouldn't be kids of that DocFrag.
191        for(DOMNode *kid=newChild->getFirstChild(); // Prescan
192              kid!=0;
193              kid=kid->getNextSibling())
194        {
195            if (!DOMDocumentImpl::isKidOK(castToNode(this), kid))
196              throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, GetDOMParentNodeMemoryManager);
197        }
198        while(newChild->hasChildNodes())     // Move
199            castToNode(this)->insertBefore(newChild->getFirstChild(),refChild);
200    }
201
202    else if (!DOMDocumentImpl::isKidOK(castToNode(this), newChild))
203        throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, GetDOMParentNodeMemoryManager);
204
205    else
206    {
207        DOMNode *oldparent=newChild->getParentNode();
208        if(oldparent!=0)
209            oldparent->removeChild(newChild);
210
211        // Attach up
212        castToNodeImpl(newChild)->fOwnerNode = castToNode(this);
213        castToNodeImpl(newChild)->isOwned(true);
214
215        // Attach before and after
216        // Note: fFirstChild.previousSibling == lastChild!!
217        if (fFirstChild == 0) {
218            // this our first and only child
219            fFirstChild = newChild;
220            castToNodeImpl(newChild)->isFirstChild(true);
221            // castToChildImpl(newChild)->previousSibling = newChild;
222            DOMChildNode *newChild_ci = castToChildImpl(newChild);
223            newChild_ci->previousSibling = newChild;
224        } else {
225            if (refChild == 0) {
226                // this is an append
227                DOMNode *lastChild = castToChildImpl(fFirstChild)->previousSibling;
228                castToChildImpl(lastChild)->nextSibling = newChild;
229                castToChildImpl(newChild)->previousSibling = lastChild;
230                castToChildImpl(fFirstChild)->previousSibling = newChild;
231            } else {
232                // this is an insert
233                if (refChild == fFirstChild) {
234                    // at the head of the list
235                    castToNodeImpl(fFirstChild)->isFirstChild(false);
236                    castToChildImpl(newChild)->nextSibling = fFirstChild;
237                    castToChildImpl(newChild)->previousSibling = castToChildImpl(fFirstChild)->previousSibling;
238                    castToChildImpl(fFirstChild)->previousSibling = newChild;
239                    fFirstChild = newChild;
240                    castToNodeImpl(newChild)->isFirstChild(true);
241                } else {
242                    // somewhere in the middle
243                    DOMNode *prev = castToChildImpl(refChild)->previousSibling;
244                    castToChildImpl(newChild)->nextSibling = refChild;
245                    castToChildImpl(prev)->nextSibling = newChild;
246                    castToChildImpl(refChild)->previousSibling = newChild;
247                    castToChildImpl(newChild)->previousSibling = prev;
248                }
249            }
250        }
251    }
252
253    changed();
254
255    if (fOwnerDocument != 0) {
256        Ranges* ranges = ((DOMDocumentImpl*)fOwnerDocument)->getRanges();
257        if ( ranges != 0) {
258            XMLSize_t sz = ranges->size();
259            if (sz != 0) {
260                for (XMLSize_t i =0; i<sz; i++) {
261                    ranges->elementAt(i)->updateRangeForInsertedNode(newChild);
262                }
263            }
264        }
265    }
266
267    return newChild;
268}
269
270
271
272DOMNode *DOMParentNode::removeChild(DOMNode *oldChild)
273{
274    if (castToNodeImpl(this)->isReadOnly())
275        throw DOMException(
276        DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMParentNodeMemoryManager);
277
278    if (oldChild == 0 || oldChild->getParentNode() != castToNode(this))
279        throw DOMException(DOMException::NOT_FOUND_ERR, 0, GetDOMParentNodeMemoryManager);
280
281    if (fOwnerDocument !=  0) {
282        //notify iterators
283        NodeIterators* nodeIterators = ((DOMDocumentImpl*)fOwnerDocument)->getNodeIterators();
284        if (nodeIterators != 0) {
285            XMLSize_t sz = nodeIterators->size();
286            if (sz != 0) {
287                for (XMLSize_t i =0; i<sz; i++) {
288                    if (nodeIterators->elementAt(i) != 0)
289                        nodeIterators->elementAt(i)->removeNode(oldChild);
290                }
291            }
292        }
293
294        //fix other ranges for change before deleting the node
295        Ranges* ranges = ((DOMDocumentImpl*)fOwnerDocument)->getRanges();
296        if (ranges != 0) {
297            XMLSize_t sz = ranges->size();
298            if (sz != 0) {
299                for (XMLSize_t i =0; i<sz; i++) {
300                    if (ranges->elementAt(i) != 0)
301                        ranges->elementAt(i)->updateRangeForDeletedNode(oldChild);
302                }
303            }
304        }
305    }
306
307
308    // Patch linked list around oldChild
309    // Note: lastChild == fFirstChild->previousSibling
310    if (oldChild == fFirstChild) {
311        // removing first child
312        castToNodeImpl(oldChild)->isFirstChild(false);
313        fFirstChild = castToChildImpl(oldChild)->nextSibling;
314        if (fFirstChild != 0) {
315            castToNodeImpl(fFirstChild)->isFirstChild(true);
316            castToChildImpl(fFirstChild)->previousSibling = castToChildImpl(oldChild)->previousSibling;
317        }
318    } else {
319        DOMNode *prev = castToChildImpl(oldChild)->previousSibling;
320        DOMNode *next = castToChildImpl(oldChild)->nextSibling;
321        castToChildImpl(prev)->nextSibling = next;
322        if (next == 0) {
323            // removing last child
324            castToChildImpl(fFirstChild)->previousSibling = prev;
325        } else {
326            // removing some other child in the middle
327            castToChildImpl(next)->previousSibling = prev;
328        }
329    }
330
331    // Remove oldChild's references to tree
332    castToNodeImpl(oldChild)->fOwnerNode = fOwnerDocument;
333    castToNodeImpl(oldChild)->isOwned(false);
334    castToChildImpl(oldChild)->nextSibling = 0;
335    castToChildImpl(oldChild)->previousSibling = 0;
336
337    changed();
338
339    return oldChild;
340}
341
342
343DOMNode *DOMParentNode::replaceChild(DOMNode *newChild, DOMNode *oldChild)
344{
345    insertBefore(newChild, oldChild);
346    // changed() already done.
347    return removeChild(oldChild);
348}
349
350
351DOMNode * DOMParentNode::appendChildFast(DOMNode *newChild)
352{
353    // This function makes the following assumptions:
354    //
355    // - newChild != 0
356    // - newChild is not read-only
357    // - newChild is not a document fragment
358    // - owner documents of this node and newChild are the same
359    // - appending newChild to this node cannot result in a cycle
360    // - DOMDocumentImpl::isKidOK (this, newChild) return true (that is,
361    //   appending newChild to this node results in a valid structure)
362    // - newChild->getParentNode() is 0
363    // - there are no ranges set for this document
364    //
365
366    // Attach up
367    castToNodeImpl(newChild)->fOwnerNode = castToNode(this);
368    castToNodeImpl(newChild)->isOwned(true);
369
370    // Attach before and after
371    // Note: fFirstChild.previousSibling == lastChild!!
372    if (fFirstChild != 0)
373    {
374        DOMNode *lastChild = castToChildImpl(fFirstChild)->previousSibling;
375        castToChildImpl(lastChild)->nextSibling = newChild;
376        castToChildImpl(newChild)->previousSibling = lastChild;
377        castToChildImpl(fFirstChild)->previousSibling = newChild;
378    }
379    else
380    {
381        // this our first and only child
382        fFirstChild = newChild;
383        castToNodeImpl(newChild)->isFirstChild(true);
384        // castToChildImpl(newChild)->previousSibling = newChild;
385        DOMChildNode *newChild_ci = castToChildImpl(newChild);
386        newChild_ci->previousSibling = newChild;
387    }
388
389    return newChild;
390}
391
392
393//Introduced in DOM Level 2
394
395void DOMParentNode::normalize()
396{
397    DOMNode *kid, *next;
398    for (kid = fFirstChild; kid != 0; kid = next)
399    {
400        next = castToChildImpl(kid)->nextSibling;
401
402        // If kid and next are both Text nodes (but _not_ CDATASection,
403        // which is a subclass of Text), they can be merged.
404        if (next != 0 &&
405            kid->getNodeType() == DOMNode::TEXT_NODE   &&
406            next->getNodeType() == DOMNode::TEXT_NODE )
407        {
408            ((DOMTextImpl *) kid)->appendData(((DOMTextImpl *) next)->getData());
409            // revisit:
410            //   should I release the removed node?
411            //   not released in case user still referencing it externally
412            removeChild(next);
413            next = kid; // Don't advance; there might be another.
414        }
415
416        // Otherwise it might be an Element, which is handled recursively
417        else
418            if (kid->getNodeType() == DOMNode::ELEMENT_NODE)
419                kid->normalize();
420    }
421
422    // changed() will have occurred when the removeChild() was done,
423    // so does not have to be reissued.
424}
425
426//Introduced in DOM Level 3
427
428bool DOMParentNode::isEqualNode(const DOMNode* arg) const
429{
430    if (arg && castToNodeImpl(this)->isSameNode(arg))
431        return true;
432
433    if (arg && castToNodeImpl(this)->isEqualNode(arg))
434    {
435        DOMNode *kid, *argKid;
436        for (kid = fFirstChild, argKid = arg->getFirstChild();
437             kid != 0 && argKid != 0;
438             kid = kid->getNextSibling(), argKid = argKid->getNextSibling())
439        {
440            if (!kid->isEqualNode(argKid))
441                return false;
442        }
443        return (kid || argKid) ? false : true;
444    }
445    return false;
446}
447
448
449//Non-standard extension
450void DOMParentNode::release()
451{
452    DOMNode *kid, *next;
453    for (kid = fFirstChild; kid != 0; kid = next)
454    {
455        next = castToChildImpl(kid)->nextSibling;
456
457        // set is Owned false before releasing its child
458        castToNodeImpl(kid)->isToBeReleased(true);
459        kid->release();
460    }
461}
462
463
464XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.