domparentnode.cpp
来自「IBM的解析xml的工具Xerces的源代码」· C++ 代码 · 共 423 行
CPP
423 行
/* * Copyright 2001-2002,2004 The Apache Software Foundation. * * Licensed 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: DOMParentNode.cpp,v 1.17 2004/09/08 13:55:52 peiyongz Exp $ */#include <xercesc/util/XercesDefs.hpp>#include <xercesc/dom/DOMException.hpp>#include <xercesc/dom/DOMNode.hpp>#include "DOMDocumentImpl.hpp"#include "DOMNodeListImpl.hpp"#include "DOMRangeImpl.hpp"#include "DOMNodeIteratorImpl.hpp"#include "DOMParentNode.hpp"#include "DOMCasts.hpp"XERCES_CPP_NAMESPACE_BEGINDOMParentNode::DOMParentNode(DOMDocument *ownerDoc) : fOwnerDocument(ownerDoc), fFirstChild(0), fChildNodeList(castToNode(this)){ }// This only makes a shallow copy, cloneChildren must also be called for a// deep cloneDOMParentNode::DOMParentNode(const DOMParentNode &other) : fChildNodeList(castToNode(this)){ this->fOwnerDocument = other.fOwnerDocument; // Need to break the association w/ original kids this->fFirstChild = 0;}void DOMParentNode::changed(){ DOMDocumentImpl *doc = (DOMDocumentImpl *)this->getOwnerDocument(); doc->changed();}int DOMParentNode::changes() const{ DOMDocumentImpl *doc = (DOMDocumentImpl *)this->getOwnerDocument(); return doc->changes();}DOMNode * DOMParentNode::appendChild(DOMNode *newChild){ return insertBefore(newChild, 0);}void DOMParentNode::cloneChildren(const DOMNode *other) { // for (DOMNode *mykid = other.getFirstChild(); for (DOMNode *mykid = other->getFirstChild(); mykid != 0; mykid = mykid->getNextSibling()) { appendChild(mykid->cloneNode(true)); }}DOMDocument * DOMParentNode::getOwnerDocument() const { return fOwnerDocument;}// unlike getOwnerDocument this is not overriden by DocumentImpl to return 0DOMDocument * DOMParentNode::getDocument() const { return fOwnerDocument;}void DOMParentNode::setOwnerDocument(DOMDocument* doc) { fOwnerDocument = doc;}DOMNodeList *DOMParentNode::getChildNodes() const { const DOMNodeList *ret = &fChildNodeList; return (DOMNodeList *)ret; // cast off const.}DOMNode * DOMParentNode::getFirstChild() const { return fFirstChild;}DOMNode * DOMParentNode::getLastChild() const{ return lastChild();}DOMNode * DOMParentNode::lastChild() const{ // last child is stored as the previous sibling of first child if (fFirstChild == 0) { return 0; } DOMChildNode *firstChild = castToChildImpl(fFirstChild); DOMNode *ret = firstChild->previousSibling; return ret;}//// revisit. Is this function used anywhere? I don't see it.//void DOMParentNode::lastChild(DOMNode *node) { // store lastChild as previous sibling of first child if (fFirstChild != 0) { DOMChildNode *firstChild = castToChildImpl(fFirstChild); firstChild->previousSibling = node; }}bool DOMParentNode::hasChildNodes() const{ return fFirstChild!=0;}DOMNode *DOMParentNode::insertBefore(DOMNode *newChild, DOMNode *refChild) { DOMNodeImpl *thisNodeImpl = castToNodeImpl(this); if (thisNodeImpl->isReadOnly()) throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMParentNodeMemoryManager); if (newChild->getOwnerDocument() != fOwnerDocument) throw DOMException(DOMException::WRONG_DOCUMENT_ERR, 0, GetDOMParentNodeMemoryManager); // Prevent cycles in the tree //only need to do this if the node has children if(newChild->hasChildNodes()) { bool treeSafe=true; for(DOMNode *a=castToNode(this)->getParentNode(); treeSafe && a!=0; a=a->getParentNode()) treeSafe=(newChild!=a); if(!treeSafe) throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, GetDOMParentNodeMemoryManager); } // refChild must in fact be a child of this node (or 0) if (refChild!=0 && refChild->getParentNode() != castToNode(this)) throw DOMException(DOMException::NOT_FOUND_ERR,0, GetDOMParentNodeMemoryManager); // if the new node has to be placed before itself, we don't have to do anything // (even worse, we would crash if we continue, as we assume they are two distinct nodes) if (refChild!=0 && newChild->isSameNode(refChild)) return newChild; if (newChild->getNodeType() == DOMNode::DOCUMENT_FRAGMENT_NODE) { // SLOW BUT SAFE: We could insert the whole subtree without // juggling so many next/previous pointers. (Wipe out the // parent's child-list, patch the parent pointers, set the // ends of the list.) But we know some subclasses have special- // case behavior they add to insertBefore(), so we don't risk it. // This approch also takes fewer bytecodes. // NOTE: If one of the children is not a legal child of this // node, throw HIERARCHY_REQUEST_ERR before _any_ of the children // have been transferred. (Alternative behaviors would be to // reparent up to the first failure point or reparent all those // which are acceptable to the target node, neither of which is // as robust. PR-DOM-0818 isn't entirely clear on which it // recommends????? // No need to check kids for right-document; if they weren't, // they wouldn't be kids of that DocFrag. for(DOMNode *kid=newChild->getFirstChild(); // Prescan kid!=0; kid=kid->getNextSibling()) { if (!DOMDocumentImpl::isKidOK(castToNode(this), kid)) throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, GetDOMParentNodeMemoryManager); } while(newChild->hasChildNodes()) // Move insertBefore(newChild->getFirstChild(),refChild); } else if (!DOMDocumentImpl::isKidOK(castToNode(this), newChild)) throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, GetDOMParentNodeMemoryManager); else { DOMNode *oldparent=newChild->getParentNode(); if(oldparent!=0) oldparent->removeChild(newChild); // Attach up castToNodeImpl(newChild)->fOwnerNode = castToNode(this); castToNodeImpl(newChild)->isOwned(true); // Attach before and after // Note: fFirstChild.previousSibling == lastChild!! if (fFirstChild == 0) { // this our first and only child fFirstChild = newChild; castToNodeImpl(newChild)->isFirstChild(true); // castToChildImpl(newChild)->previousSibling = newChild; DOMChildNode *newChild_ci = castToChildImpl(newChild); newChild_ci->previousSibling = newChild; } else { if (refChild == 0) { // this is an append DOMNode *lastChild = castToChildImpl(fFirstChild)->previousSibling; castToChildImpl(lastChild)->nextSibling = newChild; castToChildImpl(newChild)->previousSibling = lastChild; castToChildImpl(fFirstChild)->previousSibling = newChild; } else { // this is an insert if (refChild == fFirstChild) { // at the head of the list castToNodeImpl(fFirstChild)->isFirstChild(false); castToChildImpl(newChild)->nextSibling = fFirstChild; castToChildImpl(newChild)->previousSibling = castToChildImpl(fFirstChild)->previousSibling; castToChildImpl(fFirstChild)->previousSibling = newChild; fFirstChild = newChild; castToNodeImpl(newChild)->isFirstChild(true); } else { // somewhere in the middle DOMNode *prev = castToChildImpl(refChild)->previousSibling; castToChildImpl(newChild)->nextSibling = refChild; castToChildImpl(prev)->nextSibling = newChild; castToChildImpl(refChild)->previousSibling = newChild; castToChildImpl(newChild)->previousSibling = prev; } } } } changed(); if (this->getOwnerDocument() != 0) { Ranges* ranges = ((DOMDocumentImpl *)this->getOwnerDocument())->getRanges(); if ( ranges != 0) { XMLSize_t sz = ranges->size(); if (sz != 0) { for (XMLSize_t i =0; i<sz; i++) { ranges->elementAt(i)->updateRangeForInsertedNode(newChild); } } } } return newChild;}DOMNode *DOMParentNode::removeChild(DOMNode *oldChild){ if (castToNodeImpl(this)->isReadOnly()) throw DOMException( DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMParentNodeMemoryManager); if (oldChild == 0 || oldChild->getParentNode() != castToNode(this)) throw DOMException(DOMException::NOT_FOUND_ERR, 0, GetDOMParentNodeMemoryManager); if (this->getOwnerDocument() != 0 ) { //notify iterators NodeIterators* nodeIterators = ((DOMDocumentImpl *)this->getOwnerDocument())->getNodeIterators(); if (nodeIterators != 0) { XMLSize_t sz = nodeIterators->size(); if (sz != 0) { for (XMLSize_t i =0; i<sz; i++) { if (nodeIterators->elementAt(i) != 0) nodeIterators->elementAt(i)->removeNode(oldChild); } } } //fix other ranges for change before deleting the node Ranges* ranges = ((DOMDocumentImpl *)this->getOwnerDocument())->getRanges(); if (ranges != 0) { XMLSize_t sz = ranges->size(); if (sz != 0) { for (XMLSize_t i =0; i<sz; i++) { if (ranges->elementAt(i) != 0) ranges->elementAt(i)->updateRangeForDeletedNode(oldChild); } } } } // Patch linked list around oldChild // Note: lastChild == fFirstChild->previousSibling if (oldChild == fFirstChild) { // removing first child castToNodeImpl(oldChild)->isFirstChild(false); fFirstChild = castToChildImpl(oldChild)->nextSibling; if (fFirstChild != 0) { castToNodeImpl(fFirstChild)->isFirstChild(true); castToChildImpl(fFirstChild)->previousSibling = castToChildImpl(oldChild)->previousSibling; } } else { DOMNode *prev = castToChildImpl(oldChild)->previousSibling; DOMNode *next = castToChildImpl(oldChild)->nextSibling; castToChildImpl(prev)->nextSibling = next; if (next == 0) { // removing last child castToChildImpl(fFirstChild)->previousSibling = prev; } else { // removing some other child in the middle castToChildImpl(next)->previousSibling = prev; } } // Remove oldChild's references to tree castToNodeImpl(oldChild)->fOwnerNode = fOwnerDocument; castToNodeImpl(oldChild)->isOwned(false); castToChildImpl(oldChild)->nextSibling = 0; castToChildImpl(oldChild)->previousSibling = 0; changed(); return oldChild;}DOMNode *DOMParentNode::replaceChild(DOMNode *newChild, DOMNode *oldChild){ insertBefore(newChild, oldChild); // changed() already done. return removeChild(oldChild);}//Introduced in DOM Level 2void DOMParentNode::normalize(){ DOMNode *kid, *next; for (kid = fFirstChild; kid != 0; kid = next) { next = castToChildImpl(kid)->nextSibling; // If kid and next are both Text nodes (but _not_ CDATASection, // which is a subclass of Text), they can be merged. if (next != 0 && kid->getNodeType() == DOMNode::TEXT_NODE && next->getNodeType() == DOMNode::TEXT_NODE ) { ((DOMTextImpl *) kid)->appendData(((DOMTextImpl *) next)->getData()); // revisit: // should I release the removed node? // not released in case user still referencing it externally removeChild(next); next = kid; // Don't advance; there might be another. } // Otherwise it might be an Element, which is handled recursively else if (kid->getNodeType() == DOMNode::ELEMENT_NODE) kid->normalize(); } // changed() will have occurred when the removeChild() was done, // so does not have to be reissued.}//Introduced in DOM Level 3bool DOMParentNode::isEqualNode(const DOMNode* arg) const{ if (arg && castToNodeImpl(this)->isSameNode(arg)) return true; if (arg && castToNodeImpl(this)->isEqualNode(arg)) { DOMNode *kid, *argKid; for (kid = fFirstChild, argKid = arg->getFirstChild(); kid != 0 && argKid != 0; kid = kid->getNextSibling(), argKid = argKid->getNextSibling()) { if (!kid->isEqualNode(argKid)) return false; } return (kid || argKid) ? false : true; } return false;}//Non-standard extensionvoid DOMParentNode::release(){ DOMNode *kid, *next; for (kid = fFirstChild; kid != 0; kid = next) { next = castToChildImpl(kid)->nextSibling; // set is Owned false before releasing its child castToNodeImpl(kid)->isToBeReleased(true); kid->release(); }}XERCES_CPP_NAMESPACE_END
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?