diff --git a/tinyxml2.cpp b/tinyxml2.cpp index 99b5e92..772d2ae 100755 --- a/tinyxml2.cpp +++ b/tinyxml2.cpp @@ -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() { @@ -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* ele = CreateUnlinkedNode<XMLElement>( _elementPool ); diff --git a/tinyxml2.h b/tinyxml2.h index fd7f6b4..3465f2f 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 @@ -865,6 +865,21 @@ public: */ 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. The 2 nodes do not need to be in the same Document. @@ -1806,7 +1821,16 @@ public: /// Clear the document, resetting it to the initial state. void Clear(); - // internal + /** + 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 char* Identify( char* p, XMLNode** node ); // internal diff --git a/xmltest.cpp b/xmltest.cpp index d892a9e..550bf75 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 = + "<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. XMLDocument doc; if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))