From ed52328ced173530211267f06242d98fde0ca2da Mon Sep 17 00:00:00 2001 From: Michael Daumling Date: Wed, 23 Oct 2013 07:47:29 +0200 Subject: [PATCH] Insert() methods check for inserted XML to be in the same doc, and remove XML from old location if already inserted. --- tinyxml2.cpp | 25 +++++++++++++----- tinyxml2.h | 13 ++++++++++ xmltest.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 6 deletions(-) diff --git a/tinyxml2.cpp b/tinyxml2.cpp index b890cb1..7ecbf86 100755 --- a/tinyxml2.cpp +++ b/tinyxml2.cpp @@ -625,7 +625,6 @@ void XMLNode::DeleteChildren() void XMLNode::Unlink( XMLNode* child ) { - TIXMLASSERT( child->_parent == this ); if ( child == _firstChild ) { _firstChild = _firstChild->_next; } @@ -639,7 +638,6 @@ void XMLNode::Unlink( XMLNode* child ) if ( child->_next ) { child->_next->_prev = child->_prev; } - child->_parent = 0; } @@ -652,6 +650,12 @@ void XMLNode::DeleteChild( XMLNode* node ) XMLNode* XMLNode::InsertEndChild( XMLNode* addThis ) { + if (addThis->_document != _document) + return 0; + if (addThis->_parent) + addThis->_parent->Unlink( addThis ); + else + addThis->_memPool->SetTracked(); if ( _lastChild ) { TIXMLASSERT( _firstChild ); TIXMLASSERT( _lastChild->_next == 0 ); @@ -669,13 +673,18 @@ XMLNode* XMLNode::InsertEndChild( XMLNode* addThis ) addThis->_next = 0; } addThis->_parent = this; - addThis->_memPool->SetTracked(); return addThis; } XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis ) { + if (addThis->_document != _document) + return 0; + if (addThis->_parent) + addThis->_parent->Unlink( addThis ); + else + addThis->_memPool->SetTracked(); if ( _firstChild ) { TIXMLASSERT( _lastChild ); TIXMLASSERT( _firstChild->_prev == 0 ); @@ -694,13 +703,14 @@ XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis ) addThis->_next = 0; } addThis->_parent = this; - addThis->_memPool->SetTracked(); - return addThis; + return addThis; } XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ) { + if (addThis->_document != _document) + return 0; TIXMLASSERT( afterThis->_parent == this ); if ( afterThis->_parent != this ) { return 0; @@ -710,12 +720,15 @@ XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ) // The last node or the only node. return InsertEndChild( addThis ); } + if (addThis->_parent) + addThis->_parent->Unlink( addThis ); + else + addThis->_memPool->SetTracked(); addThis->_prev = afterThis; addThis->_next = afterThis->_next; afterThis->_next->_prev = addThis; afterThis->_next = addThis; addThis->_parent = this; - addThis->_memPool->SetTracked(); return addThis; } diff --git a/tinyxml2.h b/tinyxml2.h index 52f9180..d4c0919 100755 --- a/tinyxml2.h +++ b/tinyxml2.h @@ -734,6 +734,10 @@ public: /** Add a child node as the last (right) child. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the node does not + belong to the same document. */ XMLNode* InsertEndChild( XMLNode* addThis ); @@ -742,10 +746,19 @@ public: } /** Add a child node as the first (left) child. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the node does not + belong to the same document. */ XMLNode* InsertFirstChild( XMLNode* addThis ); /** Add a node after the specified child node. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the afterThis node + is not a child of this node, or if the node does not + belong to the same document. */ XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ); diff --git a/xmltest.cpp b/xmltest.cpp index 86b4ba2..80e42ea 100644 --- a/xmltest.cpp +++ b/xmltest.cpp @@ -1202,6 +1202,77 @@ int main( int argc, const char ** argv ) } } + { + // Insertion with Removal + const char* xml = "" + "" + "" + "" + "element 1text" + "" + "" + "" + ""; + const char* xmlInsideTwo = "" + "" + "" + "" + "" + "element 1text" + "" + "" + ""; + const char* xmlAfterOne = "" + "" + "" + "" + "element 1text" + "" + "" + ""; + const char* xmlAfterTwo = "" + "" + "" + "" + "" + "element 1text" + "" + ""; + + XMLDocument doc; + doc.Parse( xml ); + XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree"); + XMLElement* two = doc.RootElement()->FirstChildElement("two"); + two->InsertFirstChild(subtree); + XMLPrinter printer1( 0, true ); + doc.Accept( &printer1 ); + XMLTest( "Move node from within to ", xmlInsideTwo, printer1.CStr()); + + doc.Parse( xml ); + subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree"); + two = doc.RootElement()->FirstChildElement("two"); + doc.RootElement()->InsertAfterChild(two, subtree); + XMLPrinter printer2( 0, true ); + doc.Accept( &printer2 ); + XMLTest( "Move node from within after ", xmlAfterTwo, printer2.CStr()); + + doc.Parse( xml ); + XMLNode* one = doc.RootElement()->FirstChildElement("one"); + subtree = one->FirstChildElement("subtree"); + doc.RootElement()->InsertAfterChild(one, subtree); + XMLPrinter printer3( 0, true ); + doc.Accept( &printer3 ); + XMLTest( "Move node from within after ", xmlAfterOne, printer3.CStr()); + + doc.Parse( xml ); + subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree"); + two = doc.RootElement()->FirstChildElement("two"); + doc.RootElement()->InsertEndChild(subtree); + XMLPrinter printer4( 0, true ); + doc.Accept( &printer4 ); + XMLTest( "Move node from within after ", xmlAfterTwo, printer4.CStr()); + } + // ----------- Performance tracking -------------- { #if defined( _MSC_VER )