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

This commit is contained in:
Michael Daumling 2013-10-23 07:47:29 +02:00
parent ab42b16bac
commit ed52328ced
3 changed files with 103 additions and 6 deletions

View File

@ -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;
}

View File

@ -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 );

View File

@ -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 )