Added detach() method to strip off a root parent element, fixed bug in namespace...
authorScott Cantor <cantor.2@osu.edu>
Wed, 11 Oct 2006 15:39:41 +0000 (15:39 +0000)
committerScott Cantor <cantor.2@osu.edu>
Wed, 11 Oct 2006 15:39:41 +0000 (15:39 +0000)
xmltooling/AbstractChildlessElement.cpp
xmltooling/AbstractChildlessElement.h
xmltooling/AbstractComplexElement.cpp
xmltooling/AbstractComplexElement.h
xmltooling/AbstractDOMCachingXMLObject.cpp
xmltooling/AbstractDOMCachingXMLObject.h
xmltooling/AbstractXMLObject.cpp
xmltooling/AbstractXMLObject.h
xmltooling/XMLObject.h

index 6063134..1a37855 100644 (file)
@@ -29,3 +29,8 @@ using namespace std;
 // shared "empty" list of children for childless objects\r
 \r
 list<XMLObject*> AbstractChildlessElement::m_no_children;\r
+\r
+void AbstractChildlessElement::removeChild(XMLObject* child)\r
+{\r
+    throw XMLObjectException("Cannot remove child from a childless object.");\r
+}\r
index f903885..bb87812 100644 (file)
@@ -49,6 +49,8 @@ namespace xmltooling {
             return m_no_children;\r
         }\r
 \r
+        void removeChild(XMLObject* child);\r
+\r
     protected:\r
         AbstractChildlessElement() {}\r
         \r
index af04251..c3aa5aa 100644 (file)
@@ -30,3 +30,8 @@ using namespace xmltooling;
 AbstractComplexElement::~AbstractComplexElement() {
     std::for_each(m_children.begin(), m_children.end(), cleanup<XMLObject>());
 }
+
+void AbstractComplexElement::removeChild(XMLObject* child)
+{
+    m_children.erase(std::remove(m_children.begin(), m_children.end(), child), m_children.end());
+}
index a326359..9f71657 100644 (file)
@@ -50,6 +50,8 @@ namespace xmltooling {
             return m_children;\r
         }\r
 \r
+        void removeChild(XMLObject* child);\r
+\r
     protected:\r
         AbstractComplexElement() {}\r
         \r
index 77d508b..bee23c2 100644 (file)
@@ -130,3 +130,24 @@ XMLObject* AbstractDOMCachingXMLObject::clone() const
     }\r
     return NULL;\r
 }\r
+\r
+void AbstractDOMCachingXMLObject::detach()\r
+{\r
+    // This is an override that duplicates some of the checking in the base class but\r
+    // adds document management in preparation for deletion of the parent.\r
+\r
+    if (!getParent())\r
+        return;\r
+\r
+    if (getParent()->hasParent())\r
+        throw XMLObjectException("Cannot detach an object whose parent is itself a child.");\r
+\r
+    AbstractDOMCachingXMLObject* parent = dynamic_cast<AbstractDOMCachingXMLObject*>(getParent());\r
+    if (parent && parent->m_document) {\r
+        // Transfer control of document to me...\r
+        setDocument(parent->m_document);\r
+        parent->m_document = NULL;\r
+    }\r
+    // The rest is done by the base.\r
+    AbstractXMLObject::detach();\r
+}\r
index fc740f3..1e357b9 100644 (file)
@@ -61,6 +61,8 @@ namespace xmltooling {
     \r
         XMLObject* clone() const;\r
 \r
+        void detach();\r
+\r
      protected:\r
         AbstractDOMCachingXMLObject() : m_dom(NULL), m_document(NULL) {}\r
 \r
index 683fa09..13a7e5c 100644 (file)
@@ -138,3 +138,16 @@ XMLObject* AbstractXMLObject::prepareForAssignment(XMLObject* oldValue, XMLObjec
 \r
     return newValue;\r
 }\r
+\r
+void AbstractXMLObject::detach()\r
+{\r
+    if (!getParent())\r
+        return;\r
+    else if (getParent()->hasParent())\r
+        throw XMLObjectException("Cannot detach an object whose parent is itself a child.");\r
+\r
+    // Pull ourselves out of the parent and then blast him.\r
+    getParent()->removeChild(this);\r
+    delete m_parent;\r
+    m_parent = NULL;\r
+}\r
index dee54be..3f2e801 100644 (file)
@@ -48,6 +48,8 @@ namespace xmltooling {
             XMLString::release(&m_schemaLocation);\r
         }\r
 \r
+        void detach();\r
+\r
         const QName& getElementQName() const {\r
             return m_elementQname;\r
         }\r
@@ -57,9 +59,11 @@ namespace xmltooling {
         }\r
     \r
         void addNamespace(const Namespace& ns) const {\r
-            if (ns.alwaysDeclare() || m_namespaces.find(ns)==m_namespaces.end()) {\r
+            std::set<Namespace>::iterator i = m_namespaces.find(ns);\r
+            if (i == m_namespaces.end())\r
                 m_namespaces.insert(ns);\r
-            }\r
+            else if (ns.alwaysDeclare())\r
+                i->setAlwaysDeclare(true);\r
         }\r
     \r
         void removeNamespace(const Namespace& ns) {\r
index 21715e9..cc8e54b 100644 (file)
@@ -62,6 +62,18 @@ namespace xmltooling {
         virtual XMLObject* clone() const=0;\r
         \r
         /**\r
+         * Specialized function for detaching a child object from its parent\r
+         * <strong>while disposing of the parent</strong>.\r
+         *\r
+         * This is not a generic way of detaching any child object, but only of\r
+         * pruning a single child from the root of an XMLObject tree. If the\r
+         * detached XMLObject's parent is itself a child, an exception will be\r
+         * thrown. It's mainly useful for turning a child into the new root of\r
+         * the tree without having to clone the child.\r
+         */\r
+        virtual void detach()=0;\r
+\r
+        /**\r
          * Gets the QName for this element.  This QName <strong>MUST</strong> \r
          * contain the namespace URI, namespace prefix, and local element name.\r
          * \r
@@ -150,6 +162,15 @@ namespace xmltooling {
         virtual const std::list<XMLObject*>& getOrderedChildren() const=0;\r
 \r
         /**\r
+         * Used by a child's detach method to isolate the child from\r
+         * this parent object in preparation for destroying the parent\r
+         * (this object).\r
+         * \r
+         * @param child the child object to remove\r
+         */\r
+        virtual void removeChild(XMLObject* child)=0;\r
+\r
+        /**\r
          * Gets the DOM representation of this XMLObject, if one exists.\r
          * \r
          * @return the DOM representation of this XMLObject\r