From 7085f00e40de52981d8c630c49ec8844244948a6 Mon Sep 17 00:00:00 2001 From: Lee Thomason Date: Thu, 1 Jun 2017 18:09:43 -0700 Subject: [PATCH] deep copy and clone --- tinyxml2.cpp | 23 +++++++++++++++ tinyxml2.h | 28 ++++++++++++++++-- xmltest.cpp | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 2 deletions(-) diff --git a/tinyxml2.cpp b/tinyxml2.cpp index e9b275b..819382b 100755 --- a/tinyxml2.cpp +++ b/tinyxml2.cpp @@ -771,6 +771,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() { @@ -2006,6 +2018,17 @@ void XMLDocument::Clear() } +void XMLDocument::DeepCopy(XMLDocument* target) +{ + TIXMLASSERT(target); + TIXMLASSERT(target != this); + + target->Clear(); + for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) { + target->InsertEndChild(node->DeepClone(target)); + } +} + XMLElement* XMLDocument::NewElement( const char* name ) { TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() ); diff --git a/tinyxml2.h b/tinyxml2.h index de589bd..607d0c7 100755 --- a/tinyxml2.h +++ b/tinyxml2.h @@ -53,7 +53,7 @@ distribution. 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 # define DEBUG # endif @@ -846,6 +846,20 @@ public: */ virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0; + /** + Make a copy of this node and all of the children + of this node. + + If the 'document' is null, then the nodes will + be allocated in the current document. If specified, + memory will e allocated is the specified document. + + NOTE: This is probably not the correct tool to + copy a document, since XMLDocuments can have multiple + top level XMLNodes. You probably want XMLDocument::DeepCopy() + */ + XMLNode* DeepClone( XMLDocument* document ) const; + /** Test if 2 nodes are the same, but don't test children. The 2 nodes do not need to be in the same Document. @@ -1787,7 +1801,17 @@ public: /// Clear the document, resetting it to the initial state. void Clear(); - // internal + /** + Copies this document to a target. + The target will be completely cleared before the copy. + If you want to copy a sub-tree, see DeepClone. + + NOTE: that the 'target' must be non-null and not + the source document. + */ + void DeepCopy(XMLDocument* target); + + // internal char* Identify( char* p, XMLNode** node ); virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { diff --git a/xmltest.cpp b/xmltest.cpp index b6bb76f..499d626 100644 --- a/xmltest.cpp +++ b/xmltest.cpp @@ -1131,6 +1131,86 @@ int main( int argc, const char ** argv ) } { + // Deep Cloning of root element. + XMLDocument doc2; + XMLPrinter printer1; + { + // Make sure doc1 is deleted before we test doc2 + const char* xml = + "" + " " + " " + " Text" + ""; + 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 = + "" + "" + " " + " " + " Text" + ""; + 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 = + "" + "" + "" + " " + " " + " Text" + ""; + 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. XMLDocument doc; if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))