diff --git a/libxml++/document.cc b/libxml++/document.cc
index 0474a38..2cd754a 100644
--- a/libxml++/document.cc
+++ b/libxml++/document.cc
@@ -26,14 +26,12 @@
 
 #include <iostream>
 
-namespace
+namespace xmlpp
 {
 
-//Called by libxml whenever it constructs something,
-//such as a node or attribute.
-//This allows us to create a C++ instance for every C instance.
-void on_libxml_construct(xmlNode* node)
+void Document::create_wrapper(xmlNode* node)
 {
+  assert(node->_private==NULL);
   switch (node->type)
   {
     case XML_ELEMENT_NODE:
@@ -97,51 +95,9 @@ void on_libxml_construct(xmlNode* node)
   }
 }
 
-//Called by libxml whenever it destroys something
-//such as a node or attribute.
-//This allows us to delete the C++ instance for the C instance, if any.
-void on_libxml_destruct(xmlNode* node)
-{
-  bool bPrivateDeleted = false;
-  if (node->type == XML_DTD_NODE)
-  {
-    xmlpp::Dtd* cppDtd = static_cast<xmlpp::Dtd*>(node->_private);
-    if(cppDtd)
-    {
-      delete cppDtd;
-      bPrivateDeleted = true;
-    }
-  }
-  else if (node->type == XML_DOCUMENT_NODE)
-    // do nothing. See on_libxml_construct for an explanation
-    ;
-  else
-  {
-    xmlpp::Node* cppNode =  static_cast<xmlpp::Node*>(node->_private);
-    if(cppNode)
-    {
-      delete cppNode;
-      bPrivateDeleted = true;
-    }
-  }
-
-  //This probably isn't necessary:
-  if(bPrivateDeleted)
-    node->_private = 0;
-}
-
-} //anonymous namespace
-
-namespace xmlpp
-{
-
 Document::Init::Init()
 {
   xmlInitParser(); //Not always necessary, but necessary for thread safety.
-  xmlRegisterNodeDefault(on_libxml_construct);
-  xmlDeregisterNodeDefault(on_libxml_destruct);
-  xmlThrDefRegisterNodeDefault(on_libxml_construct);
-  xmlThrDefDeregisterNodeDefault(on_libxml_destruct);
 }
 
 Document::Init::~Init()
@@ -174,9 +130,69 @@ Document::Document(xmlDoc* doc)
 
 Document::~Document()
 {
+  free_wrappers(impl_);
   xmlFreeDoc(impl_);
 }
 
+void Document::free_wrappers(xmlAttr* attr)
+{
+  //Delete first the local one
+  delete reinterpret_cast<Attribute*>(attr->_private);
+  attr->_private=NULL;
+  assert(attr->children->next==NULL);
+  free_wrappers(attr->children);
+}
+
+void Document::free_wrappers(xmlDoc* doc)
+{
+  //Walk the children list
+  for(xmlNode* child=doc->children; child; child=child->next)
+     free_wrappers(child);
+}
+
+void Document::free_wrappers(xmlDtd* dtd)
+{
+  //Delete the local one
+  delete reinterpret_cast<Dtd*>(dtd->_private);
+  dtd->_private=NULL;
+
+  //Walk the children list
+  for(xmlNode* child=dtd->children; child; child=child->next)
+     free_wrappers(child);
+}
+
+void Document::free_wrappers(xmlNode* node)
+{
+  //Walk the children list
+  for(xmlNode* child=node->children; child; child=child->next)
+     free_wrappers(child);
+
+  //Delete the local one
+  assert(node->type!=XML_DOCUMENT_NODE);
+  switch(node->type)
+  {
+    //Node types that have no properties
+    case XML_DTD_NODE:
+      delete reinterpret_cast<Dtd*>(node->_private);
+      node->_private=NULL;
+      return;
+    case XML_ATTRIBUTE_NODE:
+    case XML_ELEMENT_DECL:
+    case XML_ATTRIBUTE_DECL:
+    case XML_ENTITY_DECL:
+      delete reinterpret_cast<Node*>(node->_private);
+      node->_private=NULL;
+      return;
+    default:
+      delete reinterpret_cast<Node*>(node->_private);
+      node->_private=NULL;
+  }
+
+  //Walk the attributes list
+  for(xmlAttr* attr=node->properties; attr; attr=attr->next)
+     free_wrappers(attr);
+}
+
 Glib::ustring Document::get_encoding() const
 {
   Glib::ustring encoding;
@@ -217,7 +233,11 @@ Element* Document::get_root_node() const
   if(root == 0)
     return 0;
   else
+  {
+    if(root->_private==NULL)
+	    create_wrapper(root);
     return reinterpret_cast<Element*>(root->_private);
+  }
 }
 
 Element* Document::create_root_node(const Glib::ustring& name,
@@ -271,6 +291,8 @@ CommentNode* Document::add_comment(const Glib::ustring& content)
 
   // Use the result, because node can be freed when merging text nodes:
   node = xmlAddChild( (xmlNode*)impl_, node);
+  if(node->_private==NULL)
+	  create_wrapper(node);
   return static_cast<CommentNode*>(node->_private);
 }
 
diff --git a/libxml++/document.h b/libxml++/document.h
index c30068c..1da52eb 100644
--- a/libxml++/document.h
+++ b/libxml++/document.h
@@ -170,6 +170,13 @@ public:
   ///Access the underlying libxml implementation.
   const _xmlDoc* cobj() const;
 
+  ///Construct the right C++ instances for a given element
+  static void create_wrapper(_xmlNode* node);
+  ///Recursively destroy the created C++ instances
+  static void free_wrappers(_xmlDtd* attr);
+  static void free_wrappers(_xmlDoc* attr);
+  static void free_wrappers(_xmlAttr* attr);
+  static void free_wrappers(_xmlNode* attr);
 protected:
   /** Retrieve an Entity.
    * The entity can be from an external subset or internally declared.
diff --git a/libxml++/nodes/element.cc b/libxml++/nodes/element.cc
index 69604f5..bb86838 100644
--- a/libxml++/nodes/element.cc
+++ b/libxml++/nodes/element.cc
@@ -7,6 +7,7 @@
 #include <libxml++/nodes/element.h>
 #include <libxml++/nodes/textnode.h>
 #include <libxml++/exceptions/internal_error.h>
+#include <libxml++/document.h>
 
 #include <libxml/tree.h>
 
@@ -25,6 +26,8 @@ Element::AttributeList Element::get_attributes()
   AttributeList attributes;
   for(xmlAttr* attr = cobj()->properties; attr; attr = attr->next)
   {
+    if(attr->_private==NULL)
+      Document::create_wrapper(reinterpret_cast<xmlNode*>(attr));
     attributes.push_back(reinterpret_cast<Attribute*>(attr->_private));
   }
 
@@ -44,6 +47,8 @@ Attribute* Element::get_attribute(const Glib::ustring& name,
     xmlAttr* attr = xmlHasProp(const_cast<xmlNode*>(cobj()), (const xmlChar*)name.c_str());
     if( attr )
     {
+      if(attr->_private==NULL)
+        Document::create_wrapper(reinterpret_cast<xmlNode*>(attr));
       return reinterpret_cast<Attribute*>(attr->_private);
     }
   }
@@ -54,6 +59,8 @@ Attribute* Element::get_attribute(const Glib::ustring& name,
                                  (const xmlChar*)ns_uri.c_str());
     if( attr )
     {
+      if(attr->_private==NULL)
+        Document::create_wrapper(reinterpret_cast<xmlNode*>(attr));
       return reinterpret_cast<Attribute*>(attr->_private);
     }
   }
@@ -95,7 +102,11 @@ Attribute* Element::set_attribute(const Glib::ustring& name, const Glib::ustring
   }
 
   if(attr)
+  {
+    if(attr->_private==NULL)
+      Document::create_wrapper(reinterpret_cast<xmlNode*>(attr));
     return reinterpret_cast<Attribute*>(attr->_private);
+  }
   else
     return 0;
 }
@@ -117,7 +128,11 @@ const TextNode* Element::get_child_text() const
   // FIXME: return only the first content node
   for(xmlNode* child = cobj()->children; child; child = child->next)
      if(child->type == XML_TEXT_NODE)
-        return static_cast<TextNode*>(child->_private);
+     {
+       if(child->_private==NULL)
+         Document::create_wrapper(child);
+       return static_cast<TextNode*>(child->_private);
+     }
 
   return 0;
 }
@@ -128,7 +143,11 @@ TextNode* Element::get_child_text()
   // What should we do instead? Update the documentation if we change this. murrayc.
   for(xmlNode* child = cobj()->children; child; child = child->next)
      if(child->type == XML_TEXT_NODE)
-        return static_cast<TextNode*>(child->_private);
+     {
+       if(child->_private==NULL)
+         Document::create_wrapper(child);
+       return static_cast<TextNode*>(child->_private);
+     }
 
   return 0;
 }
@@ -151,6 +170,8 @@ TextNode* Element::add_child_text(const Glib::ustring& content)
      // Use the result, because node can be freed when merging text nodes:
      node = xmlAddChild(cobj(), node); 
 
+     if(node->_private==NULL)
+       Document::create_wrapper(node);
      return static_cast<TextNode*>(node->_private);
   }
   return 0;
@@ -168,6 +189,8 @@ TextNode* Element::add_child_text(xmlpp::Node* previous_sibling, const Glib::ust
      // Use the result, because node can be freed when merging text nodes:
      node = xmlAddNextSibling(previous_sibling->cobj(), node); 
 
+     if(node->_private==NULL)
+       Document::create_wrapper(node);
      return static_cast<TextNode*>(node->_private);
   }
   return 0;
@@ -185,6 +208,8 @@ TextNode* Element::add_child_text_before(xmlpp::Node* next_sibling, const Glib::
      // Use the result, because node can be freed when merging text nodes:
      node = xmlAddPrevSibling(next_sibling->cobj(), node); 
 
+     if(node->_private==NULL)
+       Document::create_wrapper(node);
      return static_cast<TextNode*>(node->_private);
   }
   return 0;
@@ -226,6 +251,8 @@ CommentNode* Element::add_child_comment(const Glib::ustring& content)
  
   // Use the result, because node can be freed when merging text nodes:
   node = xmlAddChild(cobj(), node);
+  if(node->_private==NULL)
+    Document::create_wrapper(node);
   return static_cast<CommentNode*>(node->_private);
 }
 
diff --git a/libxml++/nodes/node.cc b/libxml++/nodes/node.cc
index 7cf34d3..2064039 100644
--- a/libxml++/nodes/node.cc
+++ b/libxml++/nodes/node.cc
@@ -7,6 +7,7 @@
 #include <libxml++/nodes/element.h>
 #include <libxml++/nodes/node.h>
 #include <libxml++/exceptions/internal_error.h>
+#include <libxml++/document.h>
 #include <libxml/xpath.h>
 #include <libxml/xpathInternals.h>
 #include <libxml/tree.h>
@@ -32,8 +33,14 @@ const Element* Node::get_parent() const
 
 Element* Node::get_parent()
 {
-  return cobj()->parent && cobj()->parent->type == XML_ELEMENT_NODE ? 
-            static_cast<Element*>(cobj()->parent->_private) : 0;
+  if(cobj()->parent && cobj()->parent->type == XML_ELEMENT_NODE)
+  {
+    if(cobj()->parent->_private==NULL)
+      Document::create_wrapper(cobj()->parent);
+    return static_cast<Element*>(cobj()->parent->_private);
+  }
+  else
+    return 0;
 }
 
 const Node* Node::get_next_sibling() const
@@ -43,8 +50,14 @@ const Node* Node::get_next_sibling() const
 
 Node* Node::get_next_sibling()
 {
-  return cobj()->next ? 
-	        static_cast<Node*>(cobj()->next->_private) : 0;
+  if(cobj()->next)
+  {
+    if(cobj()->next->_private==NULL)
+      Document::create_wrapper(cobj()->next);
+    return static_cast<Node*>(cobj()->next->_private);
+  }
+  else
+    return 0;
 }
 
 const Node* Node::get_previous_sibling() const
@@ -54,8 +67,14 @@ const Node* Node::get_previous_sibling() const
 
 Node* Node::get_previous_sibling()
 {
-  return cobj()->prev ? 
-            static_cast<Node*>(cobj()->prev->_private) : 0;
+  if(cobj()->prev)
+  {
+    if(cobj()->prev->_private==NULL)
+      Document::create_wrapper(cobj()->prev);
+    return static_cast<Node*>(cobj()->prev->_private);
+  }
+  else
+    return 0;
 }
 
 Node::NodeList Node::get_children(const Glib::ustring& name)
@@ -67,20 +86,11 @@ Node::NodeList Node::get_children(const Glib::ustring& name)
    NodeList children;
    do
    {
-      if(child->_private)
+      if(name.empty() || name == (const char*)child->name)
       {
-        if(name.empty() || name == (const char*)child->name)
-          children.push_back(reinterpret_cast<Node*>(child->_private));
-      }
-      else
-      {
-        //This should not happen:
-        //This is for debugging only:
-        //if(child->type == XML_ENTITY_DECL)
-        //{
-        //  xmlEntity* centity = (xmlEntity*)child;
-        //  std::cerr << "Node::get_children(): unexpected unwrapped Entity Declaration node name =" << centity->name << std::endl;
-        //}
+        if(child->_private==NULL)
+          Document::create_wrapper(child);
+        children.push_back(reinterpret_cast<Node*>(child->_private));
       }
    }
    while((child = child->next));
@@ -102,7 +112,11 @@ Element* Node::add_child(const Glib::ustring& name,
 
   _xmlNode* node = xmlAddChild(impl_, child);
   if(node)
+  {
+    if(node->_private==NULL)
+      Document::create_wrapper(node);
     return static_cast<Element*>(node->_private);
+  }
   else
      return 0;
 }
@@ -120,7 +134,11 @@ Element* Node::add_child(xmlpp::Node* previous_sibling,
 
   _xmlNode* node = xmlAddNextSibling(previous_sibling->cobj(), child);
   if(node)
+  {
+    if(node->_private==NULL)
+      Document::create_wrapper(node);
     return static_cast<Element*>(node->_private);
+  }
   else
      return 0;
 }
@@ -138,7 +156,11 @@ Element* Node::add_child_before(xmlpp::Node* next_sibling,
 
   _xmlNode* node = xmlAddPrevSibling(next_sibling->cobj(), child);
   if(node)
+  {
+    if(node->_private==NULL)
+      Document::create_wrapper(node);
     return static_cast<Element*>(node->_private);
+  }
   else
      return 0;
 }
@@ -179,6 +201,7 @@ void Node::remove_child(Node* node)
 {
   //TODO: Allow a node to be removed without deleting it, to allow it to be moved?
   //This would require a more complex memory management API.
+  Document::free_wrappers(node->cobj());
   xmlUnlinkNode(node->cobj());
   xmlFreeNode(node->cobj()); //The C++ instance will be deleted in a callback.
 }
@@ -200,6 +223,7 @@ Node* Node::import_node(const Node* node, bool recursive)
   xmlNode* added_node = xmlAddChild(this->cobj(),imported_node);
   if (!added_node)
   {
+    Document::free_wrappers(imported_node);
     xmlFreeNode(imported_node);
 
     #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
@@ -209,6 +233,8 @@ Node* Node::import_node(const Node* node, bool recursive)
     #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
   }
 
+  if(imported_node->_private==NULL)
+    Document::create_wrapper(imported_node);
   return static_cast<Node*>(imported_node->_private);
 }
 
@@ -292,6 +318,8 @@ static NodeSet find_impl(xmlXPathContext* ctxt, const Glib::ustring& xpath)
       
       //TODO: Check for other cnode->type values?
   
+      if(cnode->_private==NULL)
+        Document::create_wrapper(cnode);
       Node* cppNode = static_cast<Node*>(cnode->_private);
       nodes.push_back(cppNode);
     }
diff --git a/libxml++/parsers/textreader.cc b/libxml++/parsers/textreader.cc
index a0b71c6..e5cb971 100644
--- a/libxml++/parsers/textreader.cc
+++ b/libxml++/parsers/textreader.cc
@@ -2,6 +2,7 @@
 #include <libxml++/exceptions/internal_error.h>
 #include <libxml++/exceptions/parse_error.h>
 #include <libxml++/exceptions/validity_error.h>
+#include <libxml++/document.h>
 
 #include <libxml/xmlreader.h>
 
@@ -298,7 +299,11 @@ Node* TextReader::get_current_node()
 {
   xmlNodePtr node = xmlTextReaderCurrentNode(impl_);
   if(node)
+  {
+    if(node->_private==NULL)
+	    Document::create_wrapper(node);
     return static_cast<Node*>(node->_private);
+  }
     
   check_for_exceptions();
   return 0;
@@ -308,7 +313,11 @@ const Node* TextReader::get_current_node() const
 {
   xmlNodePtr node = xmlTextReaderCurrentNode(impl_);
   if(node)
+  {
+    if(node->_private==NULL)
+	    Document::create_wrapper(node);
     return static_cast<Node*>(node->_private);
+  }
 
   check_for_exceptions();
   return 0;
@@ -328,7 +337,12 @@ Node* TextReader::expand()
 {
   xmlNodePtr node = xmlTextReaderExpand(impl_);
   if(node)
+  if(node)
+  {
+    if(node->_private==NULL)
+	    Document::create_wrapper(node);
     return static_cast<Node*>(node->_private);
+  }
     
   check_for_exceptions();
   return 0;
diff --git a/libxml++/validators/dtdvalidator.cc b/libxml++/validators/dtdvalidator.cc
index 7d7d200..2c3528b 100644
--- a/libxml++/validators/dtdvalidator.cc
+++ b/libxml++/validators/dtdvalidator.cc
@@ -13,6 +13,7 @@
 #include "libxml++/keepblanks.h"
 #include "libxml++/exceptions/internal_error.h"
 #include "libxml++/io/istreamparserinputbuffer.h"
+#include "libxml++/document.h"
 
 #include <libxml/parserInternals.h>//For xmlCreateFileParserCtxt().
 
@@ -67,6 +68,8 @@ void DtdValidator::parse_subset(const Glib::ustring& external,const Glib::ustrin
     #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
   }
 
+  if(dtd->_private==NULL)
+    Document::create_wrapper(reinterpret_cast<xmlNode*>(dtd));
   dtd_ = static_cast<Dtd*>(dtd->_private);
 }
 
@@ -95,6 +98,8 @@ void DtdValidator::parse_stream(std::istream& in)
     #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
   }
 
+  if(dtd->_private==NULL)
+    Document::create_wrapper(reinterpret_cast<xmlNode*>(dtd));
   dtd_ = static_cast<Dtd*>(dtd->_private);
 }
 
@@ -102,7 +107,10 @@ void DtdValidator::release_underlying()
 {
   if(dtd_)
   {
-    xmlFreeDtd(dtd_->cobj());
+    //Make a local copy as the wrapper is destroyed first
+    xmlDtd* dtd=dtd_->cobj();
+    Document::free_wrappers(dtd);
+    xmlFreeDtd(dtd);
     dtd_ = 0;
   }
 }
