IDParentNode.cpp
上传用户:huihehuasu
上传日期:2007-01-10
资源大小:6948k
文件大小:14k
源码类别:

xml/soap/webservice

开发平台:

C/C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  *
  4.  * Copyright (c) 2001 The Apache Software Foundation.  All rights
  5.  * reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  *
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  *
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in
  16.  *    the documentation and/or other materials provided with the
  17.  *    distribution.
  18.  *
  19.  * 3. The end-user documentation included with the redistribution,
  20.  *    if any, must include the following acknowledgment:
  21.  *       "This product includes software developed by the
  22.  *        Apache Software Foundation (http://www.apache.org/)."
  23.  *    Alternately, this acknowledgment may appear in the software itself,
  24.  *    if and wherever such third-party acknowledgments normally appear.
  25.  *
  26.  * 4. The names "Xerces" and "Apache Software Foundation" must
  27.  *    not be used to endorse or promote products derived from this
  28.  *    software without prior written permission. For written
  29.  *    permission, please contact apache@apache.org.
  30.  *
  31.  * 5. Products derived from this software may not be called "Apache",
  32.  *    nor may "Apache" appear in their name, without prior written
  33.  *    permission of the Apache Software Foundation.
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38.  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42.  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44.  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45.  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46.  * SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Software Foundation, and was
  51.  * originally based on software copyright (c) 2001, International
  52.  * Business Machines, Inc., http://www.ibm.com .  For more information
  53.  * on the Apache Software Foundation, please see
  54.  * <http://www.apache.org/>.
  55.  */
  56. /*
  57.  * $Id: IDParentNode.cpp,v 1.5 2001/10/18 15:01:01 tng Exp $
  58.  */
  59. #include <util/XercesDefs.hpp>
  60. #include "IDOM_DOMException.hpp"
  61. #include "IDOM_Node.hpp"
  62. #include "IDDocumentImpl.hpp"
  63. #include "IDRangeImpl.hpp"
  64. #include "IDNodeListImpl.hpp"
  65. #include "IDParentNode.hpp"
  66. #include "IDCasts.hpp"
  67. IDParentNode::IDParentNode(IDOM_Document *ownerDoc)
  68.     : fOwnerDocument(ownerDoc), fChildNodeList(castToNode(this))
  69. {
  70.     fFirstChild = 0;
  71. };
  72. // This only makes a shallow copy, cloneChildren must also be called for a
  73. // deep clone
  74. IDParentNode::IDParentNode(const IDParentNode &other)  :
  75.     fChildNodeList(castToNode(this))
  76. {
  77.     this->fOwnerDocument = other.fOwnerDocument;
  78.     // Need to break the association w/ original kids
  79.     this->fFirstChild = 0;
  80. };
  81. void IDParentNode::changed()
  82. {
  83.     IDDocumentImpl *doc = (IDDocumentImpl *)(castToNodeImpl(this)->getOwnerDocument());
  84.     doc->changed();
  85. }
  86. int IDParentNode::changes() const
  87. {
  88.     IDDocumentImpl *doc = (IDDocumentImpl *)(castToNodeImpl(this)->getOwnerDocument());
  89.     return doc->changes();
  90. };
  91. IDOM_Node * IDParentNode::appendChild(IDOM_Node *newChild)
  92. {
  93.     return insertBefore(newChild, 0);
  94. };
  95. void IDParentNode::cloneChildren(const IDOM_Node *other) {
  96.   //    for (IDOM_Node *mykid = other.getFirstChild();
  97.     for (IDOM_Node *mykid = other->getFirstChild();
  98.          mykid != 0;
  99.          mykid = mykid->getNextSibling())
  100.     {
  101.         appendChild(mykid->cloneNode(true));
  102.     }
  103. }
  104. IDOM_Document * IDParentNode::getOwnerDocument() const {
  105.     return fOwnerDocument;
  106. }
  107. // unlike getOwnerDocument this is not overriden by DocumentImpl to return 0
  108. IDOM_Document * IDParentNode::getDocument() const {
  109.     return fOwnerDocument;
  110. }
  111. void IDParentNode::setOwnerDocument(IDOM_Document* doc) {
  112.     fOwnerDocument = doc;
  113. }
  114. IDOM_NodeList *IDParentNode::getChildNodes() const {
  115.     const IDOM_NodeList *ret = &fChildNodeList;
  116.     return (IDOM_NodeList *)ret;   // cast off const.
  117. };
  118. IDOM_Node * IDParentNode::getFirstChild() const {
  119.     return fFirstChild;
  120. };
  121. IDOM_Node * IDParentNode::getLastChild() const
  122. {
  123.     return lastChild();
  124. };
  125. IDOM_Node * IDParentNode::lastChild() const
  126. {
  127.     // last child is stored as the previous sibling of first child
  128.     if (fFirstChild == 0) {
  129.         return 0;
  130.     }
  131.     IDChildNode *firstChild = castToChildImpl(fFirstChild);
  132.     IDOM_Node *ret = firstChild->previousSibling;
  133.     return ret;
  134. };
  135. //
  136. //  idom_revisit.  Is this function used anywhere?  I don't see it.
  137. //
  138. void IDParentNode::lastChild(IDOM_Node *node) {
  139.     // store lastChild as previous sibling of first child
  140.     if (fFirstChild != 0) {
  141.         IDChildNode *firstChild = castToChildImpl(fFirstChild);
  142.         firstChild->previousSibling = node;
  143.     }
  144. }
  145. bool IDParentNode::hasChildNodes() const
  146. {
  147.     return fFirstChild!=0;
  148. };
  149. IDOM_Node *IDParentNode::insertBefore(IDOM_Node *newChild, IDOM_Node *refChild) {
  150.     IDNodeImpl *thisNodeImpl = castToNodeImpl(this);
  151.     if (thisNodeImpl->isReadOnly())
  152.         throw IDOM_DOMException(IDOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, 0);
  153.     if (newChild->getOwnerDocument() != fOwnerDocument)
  154.         throw IDOM_DOMException(IDOM_DOMException::WRONG_DOCUMENT_ERR, 0);
  155.     // Prevent cycles in the tree
  156.     bool treeSafe=true;
  157.     for(IDOM_Node *a=castToNode(this)->getParentNode();
  158.         treeSafe && a!=0;
  159.         a=a->getParentNode())
  160.         treeSafe=(newChild!=a);
  161.     if(!treeSafe)
  162.         throw IDOM_DOMException(IDOM_DOMException::HIERARCHY_REQUEST_ERR,0);
  163.     // refChild must in fact be a child of this node (or 0)
  164.     if (refChild!=0 && refChild->getParentNode() != castToNode(this))
  165.         throw IDOM_DOMException(IDOM_DOMException::NOT_FOUND_ERR,0);
  166.     if (newChild->getNodeType() == IDOM_Node::DOCUMENT_FRAGMENT_NODE)
  167.     {
  168.         // SLOW BUT SAFE: We could insert the whole subtree without
  169.         // juggling so many next/previous pointers. (Wipe out the
  170.         // parent's child-list, patch the parent pointers, set the
  171.         // ends of the list.) But we know some subclasses have special-
  172.         // case behavior they add to insertBefore(), so we don't risk it.
  173.         // This approch also takes fewer bytecodes.
  174.         // NOTE: If one of the children is not a legal child of this
  175.         // node, throw HIERARCHY_REQUEST_ERR before _any_ of the children
  176.         // have been transferred. (Alternative behaviors would be to
  177.         // reparent up to the first failure point or reparent all those
  178.         // which are acceptable to the target node, neither of which is
  179.         // as robust. PR-DOM-0818 isn't entirely clear on which it
  180.         // recommends?????
  181.         // No need to check kids for right-document; if they weren't,
  182.         // they wouldn't be kids of that DocFrag.
  183.         for(IDOM_Node *kid=newChild->getFirstChild(); // Prescan
  184.               kid!=0;
  185.               kid=kid->getNextSibling())
  186.         {
  187.             if (!IDDocumentImpl::isKidOK(castToNode(this), kid))
  188.               throw IDOM_DOMException(IDOM_DOMException::HIERARCHY_REQUEST_ERR,0);
  189.         }
  190.         while(newChild->hasChildNodes())     // Move
  191.             insertBefore(newChild->getFirstChild(),refChild);
  192.     }
  193.     else if (!IDDocumentImpl::isKidOK(castToNode(this), newChild))
  194.         throw IDOM_DOMException(IDOM_DOMException::HIERARCHY_REQUEST_ERR,0);
  195.     else
  196.     {
  197.         IDOM_Node *oldparent=newChild->getParentNode();
  198.         if(oldparent!=0) {
  199.             oldparent->removeChild(newChild);
  200.         }
  201.         // Attach up
  202.         castToNodeImpl(newChild)->fOwnerNode = castToNode(this);
  203.         castToNodeImpl(newChild)->isOwned(true);
  204.         // Attach before and after
  205.         // Note: fFirstChild.previousSibling == lastChild!!
  206.         if (fFirstChild == 0) {
  207.             // this our first and only child
  208.             fFirstChild = newChild;
  209.             castToNodeImpl(newChild)->isFirstChild(true);
  210.             // castToChildImpl(newChild)->previousSibling = newChild;
  211.             IDChildNode *newChild_ci = castToChildImpl(newChild);
  212.             newChild_ci->previousSibling = newChild;
  213.         } else {
  214.             if (refChild == 0) {
  215.                 // this is an append
  216.                 IDOM_Node *lastChild = castToChildImpl(fFirstChild)->previousSibling;
  217.                 castToChildImpl(lastChild)->nextSibling = newChild;
  218.                 castToChildImpl(newChild)->previousSibling = lastChild;
  219.                 castToChildImpl(fFirstChild)->previousSibling = newChild;
  220.             } else {
  221.                 // this is an insert
  222.                 if (refChild == fFirstChild) {
  223.                     // at the head of the list
  224.                     castToNodeImpl(fFirstChild)->isFirstChild(false);
  225.                     castToChildImpl(newChild)->nextSibling = fFirstChild;
  226.                     castToChildImpl(newChild)->previousSibling = castToChildImpl(fFirstChild)->previousSibling;
  227.                     castToChildImpl(fFirstChild)->previousSibling = newChild;
  228.                     fFirstChild = newChild;
  229.                     castToNodeImpl(newChild)->isFirstChild(true);
  230.                 } else {
  231.                     // somewhere in the middle
  232.                     IDOM_Node *prev = castToChildImpl(refChild)->previousSibling;
  233.                     castToChildImpl(newChild)->nextSibling = refChild;
  234.                     castToChildImpl(prev)->nextSibling = newChild;
  235.                     castToChildImpl(refChild)->previousSibling = newChild;
  236.                     castToChildImpl(newChild)->previousSibling = prev;
  237.                 }
  238.             }
  239.         }
  240.     }
  241.     changed();
  242.     if (this->getOwnerDocument() != 0) {
  243.         Ranges* ranges = ((IDDocumentImpl *)this->getOwnerDocument())->getRanges();
  244.         if ( ranges != 0) {
  245.             unsigned int sz = ranges->size();
  246.             if (sz != 0) {
  247.                 for (unsigned int i =0; i<sz; i++) {
  248.                     ranges->elementAt(i)->updateRangeForInsertedNode(newChild);
  249.                 }
  250.             }
  251.         }
  252.     }
  253.     return newChild;
  254. };
  255. IDOM_Node *IDParentNode::removeChild(IDOM_Node *oldChild)
  256. {
  257.     if (castToNodeImpl(this)->isReadOnly())
  258.         throw IDOM_DOMException(
  259.         IDOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, 0);
  260.     if (oldChild != 0 && oldChild->getParentNode() != castToNode(this))
  261.         throw IDOM_DOMException(IDOM_DOMException::NOT_FOUND_ERR, 0);
  262.     //fix other ranges for change before deleting the node
  263.     if (this->getOwnerDocument() !=  0  ) {
  264.         Ranges* ranges = ((IDDocumentImpl *)this->getOwnerDocument())->getRanges();
  265.         if (ranges != 0) {
  266.             unsigned int sz = ranges->size();
  267.             if (sz != 0) {
  268.                 for (unsigned int i =0; i<sz; i++) {
  269.                     if (ranges->elementAt(i) != 0)
  270.                         ranges->elementAt(i)->updateRangeForDeletedNode(oldChild);
  271.                 }
  272.             }
  273.         }
  274.     }
  275.     // Patch linked list around oldChild
  276.     // Note: lastChild == fFirstChild->previousSibling
  277.     if (oldChild == fFirstChild) {
  278.         // removing first child
  279.         castToNodeImpl(oldChild)->isFirstChild(false);
  280.         fFirstChild = castToChildImpl(oldChild)->nextSibling;
  281.         if (fFirstChild != 0) {
  282.             castToNodeImpl(fFirstChild)->isFirstChild(true);
  283.             castToChildImpl(fFirstChild)->previousSibling = castToChildImpl(oldChild)->previousSibling;
  284.         }
  285.     } else {
  286.         IDOM_Node *prev = castToChildImpl(oldChild)->previousSibling;
  287.         IDOM_Node *next = castToChildImpl(oldChild)->nextSibling;
  288.         castToChildImpl(prev)->nextSibling = next;
  289.         if (next == 0) {
  290.             // removing last child
  291.             castToChildImpl(fFirstChild)->previousSibling = prev;
  292.         } else {
  293.             // removing some other child in the middle
  294.             castToChildImpl(next)->previousSibling = prev;
  295.         }
  296.     }
  297.     // Remove oldChild's references to tree
  298.     castToNodeImpl(oldChild)->fOwnerNode = fOwnerDocument;
  299.     castToNodeImpl(oldChild)->isOwned(false);
  300.     castToChildImpl(oldChild)->nextSibling = 0;
  301.     castToChildImpl(oldChild)->previousSibling = 0;
  302.     changed();
  303.     return oldChild;
  304. };
  305. IDOM_Node *IDParentNode::replaceChild(IDOM_Node *newChild, IDOM_Node *oldChild)
  306. {
  307.     insertBefore(newChild, oldChild);
  308.     // changed() already done.
  309.     return removeChild(oldChild);
  310. };
  311. //Introduced in DOM Level 2
  312. void IDParentNode::normalize()
  313. {
  314.     IDOM_Node *kid, *next;
  315.     for (kid = fFirstChild; kid != 0; kid = next)
  316.     {
  317.         next = castToChildImpl(kid)->nextSibling;
  318.         // If kid and next are both Text nodes (but _not_ CDATASection,
  319.         // which is a subclass of Text), they can be merged.
  320.         if (next != 0 &&
  321.             kid->getNodeType() == IDOM_Node::TEXT_NODE   &&
  322.             next->getNodeType() == IDOM_Node::TEXT_NODE )
  323.         {
  324.             ((IDTextImpl *) kid)->appendData(((IDTextImpl *) next)->getData());
  325.             removeChild(next);
  326.             next = kid; // Don't advance; there might be another.
  327.         }
  328.         // Otherwise it might be an Element, which is handled recursively
  329.         else
  330.             if (kid->getNodeType() == IDOM_Node::ELEMENT_NODE)
  331.                 kid->normalize();
  332.     };
  333.     // changed() will have occurred when the removeChild() was done,
  334.     // so does not have to be reissued.
  335. };