ソースを参照

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

Michael Daumling 12 年 前
コミット
ed52328ced
3 ファイル変更103 行追加6 行削除
  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 )