Merge pull request #558 from leethomason/clone

Support clone (deep copy) of XMLDocument and XMLNode
This commit is contained in:
Lee Thomason 2017-06-15 12:01:48 -07:00 committed by GitHub
commit bc527554e8
3 changed files with 131 additions and 2 deletions

View File

@ -772,6 +772,18 @@ void XMLNode::SetValue( const char* str, bool staticMem )
} }
} }
XMLNode* XMLNode::DeepClone(XMLDocument* document) const
{
XMLNode* clone = this->ShallowClone(document);
if (!clone) return 0;
for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
XMLNode* childClone = child->DeepClone(document);
TIXMLASSERT(childClone);
clone->InsertEndChild(childClone);
}
return clone;
}
void XMLNode::DeleteChildren() void XMLNode::DeleteChildren()
{ {
@ -2038,6 +2050,19 @@ void XMLDocument::Clear()
} }
void XMLDocument::DeepCopy(XMLDocument* target)
{
TIXMLASSERT(target);
if (target == this) {
return; // technically success - a no-op.
}
target->Clear();
for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
target->InsertEndChild(node->DeepClone(target));
}
}
XMLElement* XMLDocument::NewElement( const char* name ) XMLElement* XMLDocument::NewElement( const char* name )
{ {
XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool ); XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );

View File

@ -53,7 +53,7 @@ distribution.
AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h
*/ */
#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__) #if defined( _DEBUG ) || defined (__DEBUG__)
# ifndef DEBUG # ifndef DEBUG
# define DEBUG # define DEBUG
# endif # endif
@ -865,6 +865,21 @@ public:
*/ */
virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0; virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
/**
Make a copy of this node and all its children.
If the 'document' is null, then the nodes will
be allocated in the current document. If document
is specified, the memory will be allocated is the
specified XMLDocument.
NOTE: This is probably not the correct tool to
copy a document, since XMLDocuments can have multiple
top level XMLNodes. You probably want to use
XMLDocument::DeepCopy()
*/
XMLNode* DeepClone( XMLDocument* document ) const;
/** /**
Test if 2 nodes are the same, but don't test children. Test if 2 nodes are the same, but don't test children.
The 2 nodes do not need to be in the same Document. The 2 nodes do not need to be in the same Document.
@ -1806,6 +1821,15 @@ public:
/// Clear the document, resetting it to the initial state. /// Clear the document, resetting it to the initial state.
void Clear(); void Clear();
/**
Copies this document to a target document.
The target will be completely cleared before the copy.
If you want to copy a sub-tree, see XMLNode::DeepClone().
NOTE: that the 'target' must be non-null.
*/
void DeepCopy(XMLDocument* target);
// internal // internal
char* Identify( char* p, XMLNode** node ); char* Identify( char* p, XMLNode** node );

View File

@ -1130,6 +1130,86 @@ int main( int argc, const char ** argv )
XMLTest( "Clone and Equal", 4, count ); XMLTest( "Clone and Equal", 4, count );
} }
{
// Deep Cloning of root element.
XMLDocument doc2;
XMLPrinter printer1;
{
// Make sure doc1 is deleted before we test doc2
const char* xml =
"<root>"
" <child1 foo='bar'/>"
" <!-- comment thing -->"
" <child2 val='1'>Text</child2>"
"</root>";
XMLDocument doc;
doc.Parse(xml);
doc.Print(&printer1);
XMLNode* root = doc.RootElement()->DeepClone(&doc2);
doc2.InsertFirstChild(root);
}
XMLPrinter printer2;
doc2.Print(&printer2);
XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
}
{
// Deep Cloning of sub element.
XMLDocument doc2;
XMLPrinter printer1;
{
// Make sure doc1 is deleted before we test doc2
const char* xml =
"<?xml version ='1.0'?>"
"<root>"
" <child1 foo='bar'/>"
" <!-- comment thing -->"
" <child2 val='1'>Text</child2>"
"</root>";
XMLDocument doc;
doc.Parse(xml);
const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
subElement->Accept(&printer1);
XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
doc2.InsertFirstChild(clonedSubElement);
}
XMLPrinter printer2;
doc2.Print(&printer2);
XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
}
{
// Deep cloning of document.
XMLDocument doc2;
XMLPrinter printer1;
{
// Make sure doc1 is deleted before we test doc2
const char* xml =
"<?xml version ='1.0'?>"
"<!-- Top level comment. -->"
"<root>"
" <child1 foo='bar'/>"
" <!-- comment thing -->"
" <child2 val='1'>Text</child2>"
"</root>";
XMLDocument doc;
doc.Parse(xml);
doc.Print(&printer1);
doc.DeepCopy(&doc2);
}
XMLPrinter printer2;
doc2.Print(&printer2);
XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
}
{ {
// This shouldn't crash. // This shouldn't crash.
XMLDocument doc; XMLDocument doc;