AttrImpl.cpp
上传用户:zhuqijet
上传日期:2013-06-25
资源大小:10074k
文件大小:23k
源码类别:

词法分析

开发平台:

Visual C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  *
  4.  * Copyright (c) 1999-2002 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) 1999, 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: AttrImpl.cpp,v 1.7 2003/05/27 03:51:07 neilg Exp $
  58.  *
  59.  * <p><b>WARNING</b>: Some of the code here is partially duplicated in
  60.  * ParentNode, be careful to keep these two classes in sync!
  61.  */
  62. #include "AttrImpl.hpp"
  63. #include "DOM_DOMException.hpp"
  64. #include "DocumentImpl.hpp"
  65. #include "TextImpl.hpp"
  66. #include "ElementImpl.hpp"
  67. #include "DStringPool.hpp"
  68. #include "NodeIDMap.hpp"
  69. #include "RangeImpl.hpp"
  70. XERCES_CPP_NAMESPACE_BEGIN
  71. /*
  72.  * The handling of the value field being either the first child node (a
  73.  * ChildNode*) or directly the value (a DOMString) is rather tricky. In the
  74.  * DOMString case we need to get the field in the right type so that the
  75.  * compiler is happy and the appropriate operator gets called. This is
  76.  * essential for the reference counts of the DOMStrings involved to be updated
  77.  * as due.
  78.  * This is consistently achieved by taking the address of the value field and
  79.  * changing it into a DOMString*, and then dereferencing it to get a DOMString.
  80.  * The typical piece of code is:
  81.  * DOMString *x = (DomString *)&value;
  82.  *  ... use of *x which is the DOMString ...
  83.  * This was amended by neilg after memory management was
  84.  * introduced.  Now a union exists which is either a 
  85.  * DOMString * or a ChildNode *.  This will be less efficient
  86.  * (one more dereference per access) but actually works on all the
  87.  * compilers we support.
  88.  */
  89. AttrImpl::AttrImpl(DocumentImpl *ownerDoc, const DOMString &aName)
  90.     : NodeImpl (ownerDoc)
  91. {
  92.     name = aName.clone();
  93.     isSpecified(true);
  94.     hasStringValue(true);
  95.     value.child = null;
  96. };
  97. AttrImpl::AttrImpl(const AttrImpl &other, bool deep)
  98.     : NodeImpl(other)
  99. {
  100.     name = other.name.clone();
  101.     isSpecified(other.isSpecified());
  102.     /* We must initialize the void* value to null in *all* cases. Failing to do
  103.      * so would cause, in case of assignment to a DOMString later, its content
  104.      * to be derefenced as a DOMString, which would lead the ref count code to
  105.      * be called on something that is not actually a DOMString... Really bad
  106.      * things would then happen!!!
  107.      */
  108.     value.child = null;
  109.     hasStringValue(other.hasStringValue());
  110.     if (other.isIdAttr())
  111.     {
  112.         isIdAttr(true);
  113.         this->getOwnerDocument()->getNodeIDMap()->add(this);
  114.     }
  115.     // take care of case where there are kids
  116.     if (!hasStringValue()) {
  117.         cloneChildren(other);
  118.     }
  119.     else {
  120.         if(other.value.str == null) 
  121.         {
  122.             if(value.str != null)
  123.             {
  124.                 *(value.str) == null;
  125.                 delete value.str;
  126.                 value.str = null;
  127.             }
  128.        }
  129.        else
  130.        {
  131.             // get the address of the value field of this as a DOMString*
  132.             DOMString *x = (value.str == null
  133.                 ?(value.str = new (getOwnerDocument()->getMemoryManager()) DOMString())
  134.                 :value.str
  135.             );
  136.             // and the address of the value field of other as a DOMString*
  137.             DOMString *y = other.value.str;
  138.             // We can now safely do the cloning and assignement, both operands
  139.             // being a DOMString their ref counts will be updated appropriately
  140.             *x = y->clone();
  141.         }
  142.     }
  143. };
  144. AttrImpl::~AttrImpl() {
  145.     if (hasStringValue()) {
  146.         // if value is a DOMString we must make sure its ref count is updated.
  147.         // this is achieved by changing the address of the value field into a
  148.         // DOMString* and setting the value field to null
  149.         if(value.str != null) 
  150.         {
  151.             *(value.str) == null;
  152.             delete value.str;
  153.             value.str = null;
  154.         }
  155.     }
  156. }
  157. // create a real Text node as child if we don't have one yet
  158. void AttrImpl::makeChildNode() {
  159.     if (hasStringValue()) {
  160.         if (value.child != null) {
  161.             // change the address of the value field into a DOMString*
  162.             DOMString *x = (value.str == null
  163.                 ?(value.str = new (getOwnerDocument()->getMemoryManager()) DOMString())
  164.                 :value.str
  165.             );
  166.             // create a Text node passing the DOMString it points to
  167.             TextImpl *text =
  168.               (TextImpl *) getOwnerDocument()->createTextNode(*x);
  169.             // get the DOMString ref count to be updated by setting the value
  170.             // field to null
  171.             *x = null;
  172.             delete x;
  173.             // finally reassign the value to the node address
  174.             value.child = text;
  175.             text->isFirstChild(true);
  176.             text->previousSibling = text;
  177.             text->ownerNode = this;
  178.             text->isOwned(true);
  179.         }
  180.         hasStringValue(false);
  181.     }
  182. }
  183. NodeImpl * AttrImpl::cloneNode(bool deep)
  184. {
  185.     return new (getOwnerDocument()->getMemoryManager()) AttrImpl(*this, deep);
  186. };
  187. DOMString AttrImpl::getNodeName() {
  188.     return name;
  189. };
  190. short AttrImpl::getNodeType() {
  191.     return DOM_Node::ATTRIBUTE_NODE;
  192. };
  193. DOMString AttrImpl::getName()
  194. {
  195.     return name;
  196. };
  197. DOMString AttrImpl::getNodeValue()
  198. {
  199.     return getValue();
  200. };
  201. bool AttrImpl::getSpecified()
  202. {
  203.     return isSpecified();
  204. };
  205. DOMString AttrImpl::getValue()
  206. {
  207.     if (value.child == null) {
  208.         return 0; // return "";
  209.     }
  210.     if (hasStringValue()) {
  211.         // change value into a DOMString*
  212.         DOMString *x = (value.str == null
  213.             ?(value.str = new (getOwnerDocument()->getMemoryManager()) DOMString())
  214.             :value.str
  215.         );
  216.         // return the DOMString it points to
  217.         return *x;
  218.     }
  219.     ChildNode *firstChild = value.child;
  220.     ChildNode *node = firstChild->nextSibling;
  221.     if (node == null) {
  222.         return firstChild->getNodeValue().clone();
  223.     }
  224.     int             length = 0;
  225.     for (node = firstChild; node != null; node = node->nextSibling)
  226.         length += node->getNodeValue().length();
  227.     DOMString retString;
  228.     retString.reserve(length);
  229.     for (node = firstChild; node != null; node = node->nextSibling)
  230.     {
  231.         retString.appendData(node->getNodeValue());
  232.     };
  233.     return retString;
  234. };
  235. bool AttrImpl::isAttrImpl()
  236. {
  237.     return true;
  238. };
  239. void AttrImpl::setNodeValue(const DOMString &val)
  240. {
  241.     setValue(val);
  242. };
  243. void AttrImpl::setSpecified(bool arg)
  244. {
  245.     isSpecified(arg);
  246. };
  247. void AttrImpl::setValue(const DOMString &newvalue)
  248. {
  249.     if (isReadOnly())
  250.     {
  251.         throw DOM_DOMException
  252.         (
  253.             DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null
  254.         );
  255.     }
  256.     //  If this attribute was of type ID and in the map, take it out,
  257.     //    then put it back in with the new name.  For now, we don't worry
  258.     //    about what happens if the new name conflicts
  259.     //
  260.     if (isIdAttr())
  261.         this->getOwnerDocument()->getNodeIDMap()->remove(this);
  262.     if (!hasStringValue() && value.str != null) {
  263.         NodeImpl *kid;
  264.         while ((kid = value.child) != null) { // Remove existing kids
  265.             removeChild(kid);
  266.             if (kid->nodeRefCount == 0)
  267.                 NodeImpl::deleteIf(kid);
  268.         }
  269.     }
  270.     // directly store the string as the value by changing the value field
  271.     // into a DOMString
  272.     DOMString *x = (value.str == null 
  273.         ?(value.str = new (getOwnerDocument()->getMemoryManager()) DOMString())
  274.         :value.str
  275.     );
  276.     if (newvalue != null) {
  277.         *x = newvalue.clone();
  278.     }
  279.     else {
  280.         *x = null;
  281.         delete x;
  282.         value.str = null;
  283.     }
  284.     hasStringValue(true);
  285.     isSpecified(true);
  286.     changed();
  287.     if (isIdAttr())
  288.         this->getOwnerDocument()->getNodeIDMap()->add(this);
  289. };
  290. DOMString AttrImpl::toString()
  291. {
  292.     DOMString retString;
  293.     retString.appendData(name);
  294.     retString.appendData(DOMString("=""));
  295.     retString.appendData(getValue());
  296.     retString.appendData(DOMString("""));
  297.     return retString;
  298. }
  299. //Introduced in DOM Level 2
  300. ElementImpl *AttrImpl::getOwnerElement()
  301. {
  302.     // if we have an owner, ownerNode is our ownerElement, otherwise it's
  303.     // our ownerDocument and we don't have an ownerElement
  304.     return (ElementImpl *) (isOwned() ? ownerNode : null);
  305. }
  306. //internal use by parser only
  307. void AttrImpl::setOwnerElement(ElementImpl *ownerElem)
  308. {
  309.     ownerNode = ownerElem;
  310.     isOwned(false);
  311. }
  312. // ParentNode stuff
  313. void AttrImpl::cloneChildren(const NodeImpl &other) {
  314.   //    for (NodeImpl *mykid = other.getFirstChild();
  315.     for (NodeImpl *mykid = ((NodeImpl&)other).getFirstChild();
  316.          mykid != null;
  317.          mykid = mykid->getNextSibling()) {
  318.         this->appendChild(mykid->cloneNode(true));
  319.     }
  320. }
  321. NodeListImpl *AttrImpl::getChildNodes() {
  322.     return this;
  323. }
  324. NodeImpl * AttrImpl::getFirstChild() {
  325.     makeChildNode();
  326.     return value.child;
  327. }
  328. NodeImpl * AttrImpl::getLastChild() {
  329.     return lastChild();
  330. }
  331. ChildNode * AttrImpl::lastChild() {
  332.     // last child is stored as the previous sibling of first child
  333.     makeChildNode();
  334.     return value.child != null ? (value.child)->previousSibling : null;
  335. }
  336. void AttrImpl::lastChild(ChildNode *node) {
  337.     // store lastChild as previous sibling of first child
  338.     if (value.child != null) {
  339.         (value.child)->previousSibling = node;
  340.     }
  341. }
  342. unsigned int AttrImpl::getLength() {
  343.     if (hasStringValue()) {
  344.         return 1;
  345.     }
  346.     ChildNode *node = value.child;
  347.     int length = 0;
  348.     while (node != null) {
  349.         length++;
  350.         node = node->nextSibling;
  351.     }
  352.     return length;
  353. }
  354. bool AttrImpl::hasChildNodes()
  355. {
  356.     return value.child != null;
  357. };
  358. NodeImpl *AttrImpl::insertBefore(NodeImpl *newChild, NodeImpl *refChild) {
  359.     DocumentImpl *ownerDocument = getOwnerDocument();
  360.     bool errorChecking = ownerDocument->getErrorChecking();
  361.     if (newChild->isDocumentFragmentImpl()) {
  362.         // SLOW BUT SAFE: We could insert the whole subtree without
  363.         // juggling so many next/previous pointers. (Wipe out the
  364.         // parent's child-list, patch the parent pointers, set the
  365.         // ends of the list.) But we know some subclasses have special-
  366.         // case behavior they add to insertBefore(), so we don't risk it.
  367.         // This approch also takes fewer bytecodes.
  368.         // NOTE: If one of the children is not a legal child of this
  369.         // node, throw HIERARCHY_REQUEST_ERR before _any_ of the children
  370.         // have been transferred. (Alternative behaviors would be to
  371.         // reparent up to the first failure point or reparent all those
  372.         // which are acceptable to the target node, neither of which is
  373.         // as robust. PR-DOM-0818 isn't entirely clear on which it
  374.         // recommends?????
  375.         // No need to check kids for right-document; if they weren't,
  376.         // they wouldn't be kids of that DocFrag.
  377.         if (errorChecking) {
  378.             for (NodeImpl *kid = newChild->getFirstChild(); // Prescan
  379.                  kid != null; kid = kid->getNextSibling()) {
  380.                 if (!DocumentImpl::isKidOK(this, kid)) {
  381.                     throw DOM_DOMException(
  382.                                        DOM_DOMException::HIERARCHY_REQUEST_ERR,
  383.                                        null);
  384.                 }
  385.             }
  386.         }
  387.         while (newChild->hasChildNodes()) {    // Move
  388.             insertBefore(newChild->getFirstChild(), refChild);
  389.         }
  390.         return newChild;
  391.     }
  392.     // it's a no-op if refChild is the same as newChild
  393.     if (refChild == newChild) {
  394.         return newChild;
  395.     }
  396.     if (errorChecking) {
  397.         if (isReadOnly()) {
  398.             throw DOM_DOMException(
  399.                                  DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR,
  400.                                  null);
  401.         }
  402.         if (newChild->getOwnerDocument() != ownerDocument) {
  403.             throw DOM_DOMException(DOM_DOMException::WRONG_DOCUMENT_ERR, null);
  404.         }
  405.         if (!DocumentImpl::isKidOK(this, newChild)) {
  406.             throw DOM_DOMException(DOM_DOMException::HIERARCHY_REQUEST_ERR,
  407.                                    null);
  408.         }
  409.         // refChild must be a child of this node (or null)
  410.         if (refChild != null && refChild->getParentNode() != this) {
  411.             throw DOM_DOMException(DOM_DOMException::NOT_FOUND_ERR, null);
  412.         }
  413.         // Prevent cycles in the tree
  414.         // newChild cannot be ancestor of this Node,
  415.         // and actually cannot be this
  416.         bool treeSafe = true;
  417.         for (NodeImpl *a = this; treeSafe && a != null; a = a->getParentNode())
  418.         {
  419.             treeSafe = (newChild != a);
  420.         }
  421.         if (!treeSafe) {
  422.             throw DOM_DOMException(DOM_DOMException::HIERARCHY_REQUEST_ERR,
  423.                                    null);
  424.         }
  425.     }
  426.     makeChildNode(); // make sure we have a node and not a string
  427.     // Convert to internal type, to avoid repeated casting
  428.     ChildNode * newInternal = (ChildNode *)newChild;
  429.     NodeImpl *oldparent = newInternal->getParentNode();
  430.     if (oldparent != null) {
  431.         oldparent->removeChild(newInternal);
  432.     }
  433.     // Convert to internal type, to avoid repeated casting
  434.     ChildNode *refInternal = (ChildNode *)refChild;
  435.     // Attach up
  436.     newInternal->ownerNode = this;
  437.     newInternal->isOwned(true);
  438.     // Attach before and after
  439.     // Note: firstChild.previousSibling == lastChild!!
  440.     ChildNode *firstChild = value.child;
  441.     if (firstChild == null) {
  442.         // this our first and only child
  443.         value.child = newInternal; // firstChild = newInternal
  444.         newInternal->isFirstChild(true);
  445.         newInternal->previousSibling = newInternal;
  446.     }
  447.     else {
  448.         if (refInternal == null) {
  449.             // this is an append
  450.             ChildNode *lastChild = firstChild->previousSibling;
  451.             lastChild->nextSibling = newInternal;
  452.             newInternal->previousSibling = lastChild;
  453.             firstChild->previousSibling = newInternal;
  454.         }
  455.         else {
  456.             // this is an insert
  457.             if (refChild == firstChild) {
  458.                 // at the head of the list
  459.                 firstChild->isFirstChild(false);
  460.                 newInternal->nextSibling = firstChild;
  461.                 newInternal->previousSibling = firstChild->previousSibling;
  462.                 firstChild->previousSibling = newInternal;
  463.                 value.child = newInternal; // firstChild = newInternal;
  464.                 newInternal->isFirstChild(true);
  465.             }
  466.             else {
  467.                 // somewhere in the middle
  468.                 ChildNode *prev = refInternal->previousSibling;
  469.                 newInternal->nextSibling = refInternal;
  470.                 prev->nextSibling = newInternal;
  471.                 refInternal->previousSibling = newInternal;
  472.                 newInternal->previousSibling = prev;
  473.             }
  474.         }
  475.     }
  476.     changed();
  477.     if (this->getOwnerDocument() != null) {
  478.         typedef RefVectorOf<RangeImpl> RangeImpls;
  479.         RangeImpls* ranges = this->getOwnerDocument()->getRanges();
  480.         if ( ranges != null) {
  481.             unsigned int sz = ranges->size();
  482.             for (unsigned int i =0; i<sz; i++) {
  483.                 ranges->elementAt(i)->updateRangeForInsertedNode(newInternal);
  484.             }
  485.         }
  486.     }
  487.     return newInternal;
  488. }
  489. NodeImpl *AttrImpl::item(unsigned int index) {
  490.     if (hasStringValue()) {
  491.         if (index != 0 || value.child == null) {
  492.             return null;
  493.         }
  494.         else {
  495.             makeChildNode();
  496.             return (NodeImpl *) (value.child);
  497.         }
  498.     }
  499.     ChildNode *nodeListNode = value.child;
  500.     for (unsigned int nodeListIndex = 0;
  501.          nodeListIndex < index && nodeListNode != null;
  502.          nodeListIndex++) {
  503.         nodeListNode = nodeListNode->nextSibling;
  504.     }
  505.     return nodeListNode;
  506. }
  507. NodeImpl *AttrImpl::removeChild(NodeImpl *oldChild) {
  508.     DocumentImpl *ownerDocument = getOwnerDocument();
  509.     if (ownerDocument->getErrorChecking()) {
  510.         if (isReadOnly()) {
  511.             throw DOM_DOMException(
  512.                                  DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR,
  513.                                  null);
  514.         }
  515.         if (oldChild == null || oldChild->getParentNode() != this) {
  516.             throw DOM_DOMException(DOM_DOMException::NOT_FOUND_ERR, null);
  517.         }
  518.     }
  519.     // fix other ranges for change before deleting the node
  520.     if (getOwnerDocument() !=  null) {
  521.         typedef RefVectorOf<RangeImpl> RangeImpls;
  522.         RangeImpls* ranges = this->getOwnerDocument()->getRanges();
  523.         if (ranges != null) {
  524.             unsigned int sz = ranges->size();
  525.             if (sz != 0) {
  526.                 for (unsigned int i =0; i<sz; i++) {
  527.                     if (ranges->elementAt(i) != null)
  528.                         ranges->elementAt(i)->updateRangeForDeletedNode(oldChild);
  529.                 }
  530.             }
  531.         }
  532.     }
  533.     ChildNode * oldInternal = (ChildNode *) oldChild;
  534.     // Patch linked list around oldChild
  535.     // Note: lastChild == firstChild->previousSibling
  536.     if (oldInternal == value.child) {
  537.         // removing first child
  538.         oldInternal->isFirstChild(false);
  539.         value.child = oldInternal->nextSibling; // firstChild = oldInternal->nextSibling
  540.         ChildNode *firstChild = value.child;
  541.         if (firstChild != null) {
  542.             firstChild->isFirstChild(true);
  543.             firstChild->previousSibling = oldInternal->previousSibling;
  544.         }
  545.     } else {
  546.         ChildNode *prev = oldInternal->previousSibling;
  547.         ChildNode *next = oldInternal->nextSibling;
  548.         prev->nextSibling = next;
  549.         if (next == null) {
  550.             // removing last child
  551.             ChildNode *firstChild = value.child;
  552.             firstChild->previousSibling = prev;
  553.         } else {
  554.             // removing some other child in the middle
  555.             next->previousSibling = prev;
  556.         }
  557.     }
  558.     // Remove oldInternal's references to tree
  559.     oldInternal->ownerNode = getOwnerDocument();
  560.     oldInternal->isOwned(false);
  561.     oldInternal->nextSibling = null;
  562.     oldInternal->previousSibling = null;
  563.     changed();
  564.     return oldInternal;
  565. };
  566. NodeImpl *AttrImpl::replaceChild(NodeImpl *newChild, NodeImpl *oldChild) {
  567.     insertBefore(newChild, oldChild);
  568.     if (newChild != oldChild) {
  569.         removeChild(oldChild);
  570.     }
  571.     // changed() already done.
  572.     return oldChild;
  573. }
  574. void AttrImpl::setReadOnly(bool readOnl, bool deep) {
  575.     NodeImpl::setReadOnly(readOnl, deep);
  576.     if (deep) {
  577.         if (hasStringValue()) {
  578.             return;
  579.         }
  580.         // Recursively set kids
  581.         for (ChildNode *mykid = value.child;
  582.              mykid != null;
  583.              mykid = mykid->nextSibling)
  584.             if(! (mykid->isEntityReference()))
  585.                 mykid->setReadOnly(readOnl,true);
  586.     }
  587. }
  588. //Introduced in DOM Level 2
  589. void AttrImpl::normalize()
  590. {
  591.     if (hasStringValue()) {
  592.         return;
  593.     }
  594.     ChildNode *kid, *next;
  595.     for (kid = value.child; kid != null; kid = next)
  596.     {
  597.         next = kid->nextSibling;
  598.         // If kid and next are both Text nodes (but _not_ CDATASection,
  599.         // which is a subclass of Text), they can be merged.
  600.         if (next != null &&
  601.             kid->isTextImpl()   && !(kid->isCDATASectionImpl())  &&
  602.             next->isTextImpl()  && !(next->isCDATASectionImpl()) )
  603.         {
  604.             ((TextImpl *) kid)->appendData(((TextImpl *) next)->getData());
  605.             removeChild(next);
  606.             if (next->nodeRefCount == 0)
  607.                 deleteIf(next);
  608.             next = kid; // Don't advance; there might be another.
  609.         }
  610.         // Otherwise it might be an Element, which is handled recursively
  611.         else
  612.             if (kid->isElementImpl())
  613.                 kid->normalize();
  614.     };
  615.     // changed() will have occurred when the removeChild() was done,
  616.     // so does not have to be reissued.
  617. };
  618. XERCES_CPP_NAMESPACE_END