Kaynağa Gözat

Insert() methods check for inserted XML to be in the same doc, and remove XML from old location if already inserted.

Michael Daumling 12 yıl önce
ebeveyn
işleme
ed52328ced
3 değiştirilmiş dosya ile 103 ekleme ve 6 silme
  1. 19 6
      tinyxml2.cpp
  2. 13 0
      tinyxml2.h
  3. 71 0
      xmltest.cpp

+ 19 - 6
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;
 }
 

+ 13 - 0
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 );
 

+ 71 - 0
xmltest.cpp

@@ -1202,6 +1202,77 @@ int main( int argc, const char ** argv )
 		}
 	}
 
+	{
+		// Insertion with Removal
+		const char* xml = "<?xml version=\"1.0\" ?>"
+			"<root>"
+			"<one>"
+			"<subtree>"
+			"<elem>element 1</elem>text<!-- comment -->"
+			"</subtree>"
+			"</one>"
+			"<two/>"
+			"</root>";
+		const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
+			"<root>"
+			"<one/>"
+			"<two>"
+			"<subtree>"
+			"<elem>element 1</elem>text<!-- comment -->"
+			"</subtree>"
+			"</two>"
+			"</root>";
+		const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
+			"<root>"
+			"<one/>"
+			"<subtree>"
+			"<elem>element 1</elem>text<!-- comment -->"
+			"</subtree>"
+			"<two/>"
+			"</root>";
+		const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
+			"<root>"
+			"<one/>"
+			"<two/>"
+			"<subtree>"
+			"<elem>element 1</elem>text<!-- comment -->"
+			"</subtree>"
+			"</root>";
+
+		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 <one> to <two>", 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 <one> after <two>", 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 <one> after <one>", 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 <one> after <two>", xmlAfterTwo, printer4.CStr());
+	}
+
 	// ----------- Performance tracking --------------
 	{
 #if defined( _MSC_VER )