Began to implement collection handling.
authorScott Cantor <cantor.2@osu.edu>
Fri, 3 Mar 2006 23:59:59 +0000 (23:59 +0000)
committerScott Cantor <cantor.2@osu.edu>
Fri, 3 Mar 2006 23:59:59 +0000 (23:59 +0000)
13 files changed:
xmltooling/AbstractDOMCachingXMLObject.cpp
xmltooling/AbstractDOMCachingXMLObject.h
xmltooling/AbstractXMLObject.h
xmltooling/XMLObject.h
xmltooling/impl/UnknownElement.h
xmltooling/io/AbstractXMLObjectMarshaller.cpp
xmltooling/util/XMLObjectChildrenList.h [new file with mode: 0644]
xmltooling/xmltooling.vcproj
xmltoolingtest/MarshallingTest.h
xmltoolingtest/UnmarshallingTest.h
xmltoolingtest/XMLObjectBaseTestCase.h
xmltoolingtest/data/SimpleXMLObjectWithChildren.xml
xmltoolingtest/xmltoolingtest.vcproj

index 750e3f9..c1cd6e2 100644 (file)
@@ -23,6 +23,8 @@
 #include "internal.h"\r
 #include "exceptions.h"\r
 #include "AbstractDOMCachingXMLObject.h"\r
+#include "io/Unmarshaller.h"\r
+#include "util/XMLHelper.h"\r
 \r
 #include <algorithm>\r
 #include <functional>\r
@@ -50,23 +52,27 @@ void AbstractDOMCachingXMLObject::setDOM(DOMElement* dom, bool bindDocument)
 \r
 void AbstractDOMCachingXMLObject::releaseDOM()\r
 {\r
-    Category& log=Category::getInstance(XMLTOOLING_LOGCAT".DOM");\r
-    if (log.isDebugEnabled()) {\r
-        string qname=getElementQName().toString();\r
-        log.debug("releasing cached DOM representation for (%s)", qname.empty() ? "unknown" : qname.c_str());\r
+    if (m_dom) {\r
+        Category& log=Category::getInstance(XMLTOOLING_LOGCAT".DOM");\r
+        if (log.isDebugEnabled()) {\r
+            string qname=getElementQName().toString();\r
+            log.debug("releasing cached DOM representation for (%s)", qname.empty() ? "unknown" : qname.c_str());\r
+        }\r
+        setDOM(NULL);\r
     }\r
-    setDOM(NULL);\r
 }\r
 \r
 void AbstractDOMCachingXMLObject::releaseParentDOM(bool propagateRelease)\r
 {\r
     DOMCachingXMLObject* domCachingParent = dynamic_cast<DOMCachingXMLObject*>(getParent());\r
     if (domCachingParent) {\r
-        Category::getInstance(XMLTOOLING_LOGCAT".DOM").debug(\r
-            "releasing cached DOM representation for parent object with propagation set to %s",\r
-            propagateRelease ? "true" : "false"\r
-            );\r
-        domCachingParent->releaseDOM();\r
+        if (domCachingParent->getDOM()) {\r
+            Category::getInstance(XMLTOOLING_LOGCAT".DOM").debug(\r
+                "releasing cached DOM representation for parent object with propagation set to %s",\r
+                propagateRelease ? "true" : "false"\r
+                );\r
+            domCachingParent->releaseDOM();\r
+        }\r
         if (propagateRelease)\r
             domCachingParent->releaseParentDOM(propagateRelease);\r
     }\r
@@ -86,13 +92,12 @@ public:
 \r
 void AbstractDOMCachingXMLObject::releaseChildrenDOM(bool propagateRelease)\r
 {\r
-    vector<XMLObject*> children;\r
-    if (getOrderedChildren(children)) {\r
+    if (hasChildren()) {\r
         Category::getInstance(XMLTOOLING_LOGCAT".DOM").debug(\r
             "releasing cached DOM representation for children with propagation set to %s",\r
             propagateRelease ? "true" : "false"\r
             );\r
-        for_each(children.begin(),children.end(),bind2nd(_release(),propagateRelease));\r
+        for_each(m_children.begin(),m_children.end(),bind2nd(_release(),propagateRelease));\r
     }\r
 }\r
 \r
@@ -120,3 +125,36 @@ XMLObject* AbstractDOMCachingXMLObject::prepareForAssignment(const XMLObject* ol
 \r
     return newValue;\r
 }\r
+\r
+DOMElement* AbstractDOMCachingXMLObject::cloneDOM(DOMDocument* doc) const\r
+{\r
+    if (getDOM()) {\r
+        if (!doc)\r
+            doc=DOMImplementationRegistry::getDOMImplementation(NULL)->createDocument();\r
+        return static_cast<DOMElement*>(doc->importNode(getDOM(),true));\r
+    }\r
+    return NULL;\r
+}\r
+\r
+XMLObject* AbstractDOMCachingXMLObject::clone() const\r
+{\r
+    // See if we can clone via the DOM.\r
+    DOMElement* domCopy=cloneDOM();\r
+    if (domCopy) {\r
+        // Seemed to work, so now we unmarshall the DOM to produce the clone.\r
+        const Unmarshaller* u=Unmarshaller::getUnmarshaller(domCopy);\r
+        if (!u) {\r
+            auto_ptr<QName> q(XMLHelper::getNodeQName(domCopy));\r
+            Category::getInstance(XMLTOOLING_LOGCAT".DOM").error(\r
+                "DOM clone failed, unable to locate unmarshaller for element (%s)", q->toString().c_str()\r
+                );\r
+        }\r
+        try {\r
+            return u->unmarshall(domCopy, true);    // bind document\r
+        }\r
+        catch (...) {\r
+            domCopy->getOwnerDocument()->release();\r
+        }\r
+    }\r
+    return NULL;\r
+}\r
index 9622d1c..862f925 100644 (file)
@@ -35,6 +35,7 @@ namespace xmltooling {
 \r
     /**\r
      * Extension of AbstractXMLObject that implements a DOMCachingXMLObject.\r
+     * This is the primary base class for XMLObject implementation classes to use.\r
      */\r
     class XMLTOOL_API AbstractDOMCachingXMLObject : public AbstractXMLObject, public DOMCachingXMLObject\r
     {\r
@@ -97,8 +98,30 @@ namespace xmltooling {
             }\r
         }\r
     \r
+        /**\r
+         * @see XMLObject::clone()\r
+         */\r
+        XMLObject* clone() const;\r
+\r
      protected:\r
         /**\r
+         * Constructor\r
+         * \r
+         * @param namespaceURI the namespace the element is in\r
+         * @param elementLocalName the local name of the XML element this Object represents\r
+         */\r
+        AbstractDOMCachingXMLObject(const XMLCh* namespaceURI=NULL, const XMLCh* elementLocalName=NULL, const XMLCh* namespacePrefix=NULL)\r
+            : AbstractXMLObject(namespaceURI,elementLocalName, namespacePrefix), m_dom(NULL), m_document(NULL) {}\r
+\r
+        /**\r
+         * If a DOM representation exists, this clones it into a new document.\r
+         * \r
+         * @param doc   the document to clone into, or NULL, in which case a new document is created\r
+         * @return  the cloned DOM\r
+         */\r
+        DOMElement* cloneDOM(DOMDocument* doc=NULL) const;\r
+\r
+        /**\r
          * A helper function for derived classes.\r
          * This 'normalizes' newString and then if it is different from oldString\r
          * invalidates the DOM. It returns the normalized value.\r
@@ -132,15 +155,6 @@ namespace xmltooling {
          */\r
         XMLObject* prepareForAssignment(const XMLObject* oldValue, XMLObject* newValue);\r
 \r
-        /**\r
-         * Constructor\r
-         * \r
-         * @param namespaceURI the namespace the element is in\r
-         * @param elementLocalName the local name of the XML element this Object represents\r
-         */\r
-        AbstractDOMCachingXMLObject(const XMLCh* namespaceURI=NULL, const XMLCh* elementLocalName=NULL, const XMLCh* namespacePrefix=NULL)\r
-            : AbstractXMLObject(namespaceURI,elementLocalName, namespacePrefix), m_dom(NULL), m_document(NULL) {}\r
-\r
     private:\r
         DOMElement* m_dom;\r
         DOMDocument* m_document;\r
index 0eeae30..c3aa289 100644 (file)
@@ -23,6 +23,7 @@
 #if !defined(__xmltooling_abstractxmlobj_h__)\r
 #define __xmltooling_abstractxmlobj_h__\r
 \r
+#include <algorithm>\r
 #include <xmltooling/XMLObject.h>\r
 \r
 #if defined (_MSC_VER)\r
@@ -40,6 +41,7 @@ namespace xmltooling {
     public:\r
         virtual ~AbstractXMLObject() {\r
             delete m_typeQname;\r
+            std::for_each(m_children.begin(), m_children.end(), cleanup<XMLObject>());\r
         }\r
 \r
         /**\r
@@ -118,7 +120,21 @@ namespace xmltooling {
         void setParent(XMLObject* parent) {\r
             m_parent = parent;\r
         }\r
-    \r
+\r
+        /**\r
+         * @see XMLObject::hasChildren()\r
+         */\r
+        bool hasChildren() const {\r
+            return !m_children.empty();\r
+        }\r
+\r
+        /**\r
+         * @see XMLObject::getOrderedChildren()\r
+         */\r
+        const std::list<XMLObject*>& getOrderedChildren() const {\r
+            return m_children;\r
+        }\r
+\r
      protected:\r
         /**\r
          * Constructor\r
@@ -130,6 +146,12 @@ namespace xmltooling {
             : m_elementQname(namespaceURI,elementLocalName, namespacePrefix), m_typeQname(NULL), m_parent(NULL) {\r
             addNamespace(Namespace(namespaceURI, namespacePrefix));\r
         }\r
+\r
+        /**\r
+         * Underlying list of child objects.\r
+         * Manages the lifetime of the children.\r
+         */\r
+        std::list<XMLObject*> m_children;\r
         \r
     private:\r
         XMLObject* m_parent;\r
index 83e003e..e8fb52a 100644 (file)
@@ -134,17 +134,16 @@ namespace xmltooling {
         virtual bool hasChildren() const=0;\r
         \r
         /**\r
-         * Stores an unmodifiable list of child objects in the order that they\r
-         * will appear in the serialized representation.\r
+         * Returns an unmodifiable list of child objects in the order that they\r
+         * should appear in the serialized representation.\r
          * \r
-         * The validity of the returned objects is not maintained if any non-const\r
+         * The validity of the returned list is not maintained if any non-const\r
          * operations are performed on the parent object. \r
          * \r
-         * @param v     vector in which to store pointers to child objects\r
-         * @return the number of children\r
+         * @return the list of children\r
          */\r
-        virtual size_t getOrderedChildren(std::vector<XMLObject*>& v) const=0;\r
- };\r
+        virtual const std::list<XMLObject*>& getOrderedChildren() const=0;\r
   };\r
 \r
 };\r
 \r
index c22fa55..aff3ae5 100644 (file)
@@ -58,20 +58,6 @@ namespace xmltooling {
           */\r
         XMLObject* clone() const;\r
 \r
-        /**\r
-         * @see XMLObject::hasChildren()\r
-         */\r
-        bool hasChildren() const {\r
-            return false;\r
-        }\r
-\r
-        /**\r
-         * @see XMLObject::getOrderedChildren()\r
-         */\r
-        size_t getOrderedChildren(std::vector<XMLObject*>& v) const {\r
-            return 0;\r
-        }\r
-\r
     protected:\r
         /**\r
          * When needed, we can serialize the DOM into XML form and preserve it here.\r
index 65bc509..42a4080 100644 (file)
@@ -283,6 +283,8 @@ class _marshallchild : public binary_function<XMLObject*,DOMElement*,void> {
 public:\r
     _marshallchild(void* log) : m_log(log) {}\r
     void operator()(XMLObject* obj, DOMElement* element) const {\r
+        if (!obj)\r
+            return;\r
         if (XT_log.isDebugEnabled()) {\r
             XT_log.debug("getting marshaller for child XMLObject: %s", obj->getElementQName().toString().c_str());\r
         }\r
@@ -303,8 +305,6 @@ void AbstractXMLObjectMarshaller::marshallChildElements(const XMLObject& xmlObje
 {\r
     XT_log.debug("marshalling child elements for XMLObject");\r
 \r
-    vector<XMLObject*> children;\r
-    if (xmlObject.getOrderedChildren(children)) {\r
-        for_each(children.begin(),children.end(),bind2nd(_marshallchild(m_log),domElement));\r
-    }\r
+    const list<XMLObject*>& children=xmlObject.getOrderedChildren();\r
+    for_each(children.begin(),children.end(),bind2nd(_marshallchild(m_log),domElement));\r
 }\r
diff --git a/xmltooling/util/XMLObjectChildrenList.h b/xmltooling/util/XMLObjectChildrenList.h
new file mode 100644 (file)
index 0000000..b528798
--- /dev/null
@@ -0,0 +1,284 @@
+/*\r
+ *  Copyright 2001-2006 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/**\r
+ * @file XMLObjectChildrenList.h\r
+ * \r
+ * STL-compatible container wrapper\r
+ */\r
+\r
+#if !defined(__xmltooling_list_h__)\r
+#define __xmltooling_list_h__\r
+\r
+#include <xmltooling/DOMCachingXMLObject.h>\r
+#include <xmltooling/exceptions.h>\r
+\r
+#define ListOf(type) xmltooling::XMLObjectChildrenList<type>\r
+\r
+namespace xmltooling {\r
+\r
+    // Forward reference\r
+    template <class _Tx, class _Ty=XMLObject> class XMLObjectChildrenList;\r
+\r
+    /**\r
+     * STL iterator that mediates access to an iterator over typed XML children.\r
+     * @param _Ty   a bidrectional sequence of the subtype to iterate over\r
+     */\r
+    template <class _Ty>\r
+    class XMLObjectChildrenIterator\r
+    {\r
+        typename _Ty::iterator m_iter;\r
+        template <class _Tx, class _Ty> friend class XMLObjectChildrenList;\r
+    public:\r
+        typedef typename _Ty::iterator::iterator_category iterator_category;\r
+        typedef typename _Ty::iterator::value_type value_type;\r
+           typedef typename _Ty::iterator::reference reference;\r
+           typedef typename _Ty::iterator::pointer pointer;\r
+        typedef typename _Ty::const_iterator::reference const_reference;\r
+           typedef typename _Ty::const_iterator::pointer const_pointer;\r
+           typedef typename _Ty::iterator::difference_type difference_type;\r
+\r
+           XMLObjectChildrenIterator() {\r
+           }\r
+\r
+           XMLObjectChildrenIterator(typename _Ty::iterator& iter) {\r
+                   m_iter=iter;\r
+           }\r
+\r
+           const_reference operator*() const {\r
+                   return *m_iter;\r
+           }\r
+\r
+        pointer operator->() const {\r
+            return (&**this);\r
+           }\r
+\r
+           XMLObjectChildrenIterator& operator++() {\r
+                   // preincrement\r
+                   ++m_iter;\r
+                   return (*this);\r
+           }\r
+\r
+           XMLObjectChildrenIterator& operator--() {\r
+                   // predecrement\r
+                   --m_iter;\r
+                   return (*this);\r
+           }\r
+\r
+           XMLObjectChildrenIterator operator++(int) {\r
+                   // postincrement\r
+                   XMLObjectChildrenIterator _Tmp = *this;\r
+                   ++*this;\r
+                   return (_Tmp);\r
+           }\r
+\r
+           XMLObjectChildrenIterator operator--(int) {\r
+                   // postdecrement\r
+                   XMLObjectChildrenIterator _Tmp = *this;\r
+                   --*this;\r
+                   return (_Tmp);\r
+           }\r
+\r
+        XMLObjectChildrenIterator& operator+=(difference_type _Off) {\r
+            // increment by integer\r
+            m_iter += _Off;\r
+            return (*this);\r
+        }\r
+\r
+        XMLObjectChildrenIterator operator+(difference_type _Off) const {\r
+            // return this + integer\r
+            XMLObjectChildrenIterator _Tmp = *this;\r
+            return (_Tmp += _Off);\r
+        }\r
+\r
+        XMLObjectChildrenIterator& operator-=(difference_type _Off) {\r
+            // decrement by integer\r
+            return (*this += -_Off);\r
+        }\r
+\r
+        XMLObjectChildrenIterator operator-(difference_type _Off) const {\r
+            // return this - integer\r
+            XMLObjectChildrenIterator _Tmp = *this;\r
+            return (_Tmp -= _Off);\r
+        }\r
+\r
+        difference_type operator-(const XMLObjectChildrenIterator& _Right) const {\r
+            // return difference of iterators\r
+            return m_iter - _Right.m_iter);\r
+        }\r
+\r
+        const_reference operator[](difference_type _Off) const {\r
+            // subscript\r
+            return (*(*this + _Off));\r
+        }\r
+\r
+        bool operator==(const XMLObjectChildrenIterator &_Right) const {\r
+                   // test for iterator equality\r
+                   return (m_iter == _Right.m_iter);\r
+           }\r
+\r
+           bool operator!=(const XMLObjectChildrenIterator &_Right) const {\r
+                   // test for iterator inequality\r
+                   return (!(m_iter == _Right.m_iter));\r
+           }\r
+    };\r
+\r
+    /**\r
+     * STL-compatible container that mediates access to underlying lists of typed XML children.\r
+     * @param _Tx   the subtype to expose a container over\r
+     * @param _Ty   the base type in the underlying list (defaults to XMLObject)\r
+     */\r
+    template <class _Tx, class _Ty>\r
+    class XMLObjectChildrenList\r
+    {\r
+        typedef typename std::vector<_Tx*> container;\r
+        typename container& m_vector;\r
+        typename std::list<_Ty*>& m_list;\r
+        typename std::list<_Ty*>::iterator m_fence;\r
+        XMLObject* m_parent;\r
+\r
+       public:\r
+        typedef typename container::value_type value_type;\r
+        typedef typename container::reference reference;\r
+        typedef typename container::const_reference const_reference;\r
+        typedef typename container::difference_type difference_type;\r
+        typedef typename container::size_type size_type;\r
+\r
+        // We override the iterator types with our constrained wrapper.\r
+        typedef XMLObjectChildrenIterator<typename container> iterator;\r
+           typedef const XMLObjectChildrenIterator<typename container> const_iterator;\r
+\r
+        /**\r
+         * Constructor to expose a typed collection of children backed by a list of a base type.\r
+         *\r
+         * @param parent    parent object of the collection\r
+         * @param v         underlying vector of iterators that reference the children\r
+         * @param backing   backing list for children\r
+         * @param ins_fence a marker designating where new children of this type should be added\r
+         */\r
+           XMLObjectChildrenList(\r
+            XMLObject* parent,\r
+            typename container& v,\r
+            typename std::list<_Ty*>& backing,\r
+            typename std::list<_Ty*>::iterator ins_fence\r
+            ) : m_parent(parent), m_vector(v), m_list(backing), m_fence(ins_fence) {\r
+           }\r
+\r
+           size_type size() const {\r
+                   // return length of sequence\r
+                   return m_vector.size();\r
+           }\r
+\r
+           bool empty() const {\r
+                   // test if sequence is empty\r
+                   return m_vector.empty();\r
+           }\r
+\r
+           iterator begin() {\r
+                   // return iterator for beginning of mutable sequence\r
+                   return m_vector.begin();\r
+           }\r
+\r
+           iterator end() {\r
+                   // return iterator for end of mutable sequence\r
+                   return m_vector.end();\r
+           }\r
+\r
+           const_iterator begin() const {\r
+                   // return iterator for beginning of const sequence\r
+                   return m_vector.begin();\r
+           }\r
+\r
+           const_iterator end() const {\r
+                   // return iterator for end of const sequence\r
+                   return m_vector.end();\r
+           }\r
+\r
+        const_reference at(size_type _Pos) const {\r
+            // subscript nonmutable sequence with checking\r
+            return m_vector.at(_Pos);\r
+        }\r
+\r
+        const_reference operator[](size_type _Pos) const {\r
+            // subscript nonmutable sequence\r
+            return m_vector[_Pos];\r
+        }\r
+\r
+        const_reference front() const {\r
+            // return first element of nonmutable sequence\r
+            return (*begin());\r
+        }\r
+\r
+        const_reference back() const {\r
+            // return last element of nonmutable sequence\r
+            return *(m_vector.back());\r
+        }\r
+\r
+           void push_back(const_reference _Val) {\r
+               setParent(_Val);\r
+            m_list.insert(m_fence,_Val);\r
+            m_vector.push_back(_Val);\r
+           }\r
+\r
+        iterator erase(iterator _Where) {\r
+            removeParent(*_Where);\r
+            removeChild(*_Where);\r
+            return m_vector.erase(_Where.m_iter);\r
+        }\r
+\r
+        iterator erase(iterator _First, iterator _Last) {\r
+            for (iterator i=_First; i!=_Last; i++) {\r
+                removeParent(*i);\r
+                removeChild(*i);\r
+            }\r
+            return m_vector.erase(_First,_Last);\r
+        }\r
+\r
+    private:\r
+        void setParent(const_reference _Val) {\r
+            if (_Val->getParent())\r
+                throw XMLObjectException("Child object already has a parent.");\r
+            _Val->setParent(m_parent);\r
+            DOMCachingXMLObject* dc=dynamic_cast<DOMCachingXMLObject*>(_Val);\r
+            if (dc) {\r
+                dc->releaseParentDOM(true);\r
+            }\r
+        }\r
+\r
+        void removeParent(const_reference _Val) {\r
+            if (_Val->getParent()!=m_parent)\r
+                throw XMLObjectException("Child object not owned by this parent.");\r
+            _Val->setParent(NULL);\r
+            DOMCachingXMLObject* dc=dynamic_cast<DOMCachingXMLObject*>(m_parent);\r
+            if (dc) {\r
+                dc->releaseParentDOM(true);\r
+            }\r
+        }\r
+\r
+        void removeChild(const_reference _Val) {\r
+            for (typename std::list<_Ty*>::iterator i=m_list.begin(); i!=m_list.end(); i++) {\r
+                if ((*i)==_Val) {\r
+                    m_list.erase(i);\r
+                    delete _Val;\r
+                    return;\r
+                }\r
+            }\r
+        }\r
+    };\r
+\r
+};\r
+\r
+#endif /* __xmltooling_list_h__ */\r
index 6a651d8..c2dff62 100644 (file)
                                        RelativePath=".\util\XMLHelper.h"\r
                                        >\r
                                </File>\r
+                               <File\r
+                                       RelativePath=".\util\XMLObjectChildrenList.h"\r
+                                       >\r
+                               </File>\r
                        </Filter>\r
                        <Filter\r
                                Name="io"\r
index d8294b1..dd476c9 100644 (file)
@@ -81,8 +81,17 @@ public:
         \r
         auto_ptr<SimpleXMLObject> sxObject(dynamic_cast<SimpleXMLObject*>(b->buildObject()));\r
         TS_ASSERT(sxObject.get()!=NULL);\r
-        sxObject->getSimpleXMLObjects().push_back(dynamic_cast<SimpleXMLObject*>(b->buildObject()));\r
-        sxObject->getSimpleXMLObjects().push_back(dynamic_cast<SimpleXMLObject*>(b->buildObject()));\r
+        ListOf(SimpleXMLObject) kids=sxObject->getSimpleXMLObjects();\r
+        kids.push_back(dynamic_cast<SimpleXMLObject*>(b->buildObject()));\r
+        kids.push_back(dynamic_cast<SimpleXMLObject*>(b->buildObject()));\r
+        kids.push_back(dynamic_cast<SimpleXMLObject*>(b->buildObject()));\r
+        \r
+        // Test some collection stuff\r
+        auto_ptr_XMLCh foo("Foo");\r
+        auto_ptr_XMLCh bar("Bar");\r
+        kids[0]->setId(foo.get());\r
+        kids.at(2)->setValue(bar.get());\r
+        kids.erase(kids.begin()+1);\r
         \r
         DOMElement* rootElement = Marshaller::getMarshaller(sxObject.get())->marshall(sxObject.get());\r
 \r
index d4ba4f6..a5c87a4 100644 (file)
@@ -108,7 +108,8 @@ public:
         auto_ptr<SimpleXMLObject> sxObject(dynamic_cast<SimpleXMLObject*>(u->unmarshall(doc->getDocumentElement(),true)));\r
         TS_ASSERT(sxObject.get()!=NULL);\r
 \r
-        TSM_ASSERT_EQUALS("Number of child elements was not expected value", 2, sxObject->getSimpleXMLObjects().size());\r
+        ListOf(SimpleXMLObject) kids=sxObject->getSimpleXMLObjects();\r
+        TSM_ASSERT_EQUALS("Number of child elements was not expected value", 2, kids.size());\r
     }\r
 \r
     void testUnmarshallingWithUnknownChild() {\r
index a6e999d..d69e1c0 100644 (file)
@@ -22,6 +22,7 @@
 #include <xmltooling/io/AbstractXMLObjectMarshaller.h>\r
 #include <xmltooling/io/AbstractXMLObjectUnmarshaller.h>\r
 #include <xmltooling/util/ParserPool.h>\r
+#include <xmltooling/util/XMLObjectChildrenList.h>\r
 #include <xmltooling/util/XMLHelper.h>\r
 \r
 using namespace xmltooling;\r
@@ -50,7 +51,6 @@ public:
     virtual ~SimpleXMLObject() {\r
         XMLString::release(&m_id);\r
         XMLString::release(&m_value);\r
-        for_each(m_children.begin(), m_children.end(), cleanup<SimpleXMLObject>());\r
     }\r
     \r
     const XMLCh* getId() const { return m_id; }\r
@@ -60,15 +60,19 @@ public:
     void setValue(const XMLCh* value) { m_value=prepareForAssignment(m_value,value); }\r
     \r
     // TODO: Leave non-const, but wrap STL container to intercept adds. \r
-    list<SimpleXMLObject*>& getSimpleXMLObjects() { return m_children; }\r
-    \r
-    bool hasChildren() const { return !m_children.empty(); }\r
-    size_t getOrderedChildren(vector<XMLObject*>& children) const {\r
-        children.assign(m_children.begin(),m_children.end());\r
-        return children.size();\r
+    ListOf(SimpleXMLObject) getSimpleXMLObjects() {\r
+        return ListOf(SimpleXMLObject)(this, m_simples, m_children, m_children.end());\r
     }\r
+    \r
     SimpleXMLObject* clone() const {\r
-        SimpleXMLObject* ret=new SimpleXMLObject();\r
+        auto_ptr<XMLObject> domClone(AbstractDOMCachingXMLObject::clone());\r
+        SimpleXMLObject* ret=dynamic_cast<SimpleXMLObject*>(domClone.get());\r
+        if (ret) {\r
+            domClone.release();\r
+            return ret;\r
+        }\r
+\r
+        ret=new SimpleXMLObject();\r
         ret->setId(m_id);\r
         ret->setValue(m_value);\r
         xmltooling::clone(m_children, ret->m_children);\r
@@ -78,7 +82,7 @@ public:
 private:\r
     XMLCh* m_id;\r
     XMLCh* m_value;\r
-    list<SimpleXMLObject*> m_children;\r
+    vector<SimpleXMLObject*> m_simples;\r
     \r
     friend class SimpleXMLObjectUnmarshaller;\r
 };\r
@@ -127,6 +131,7 @@ private:
         SimpleXMLObject* child = dynamic_cast<SimpleXMLObject*>(childXMLObject);\r
         if (child) {\r
             simpleXMLObject.m_children.push_back(child);\r
+            simpleXMLObject.m_simples.push_back(child);\r
         }\r
         else {\r
             throw UnmarshallingException("Unknown child element cannot be added to parent object.");\r
index ce437ed..f8a9f67 100644 (file)
Binary files a/xmltoolingtest/data/SimpleXMLObjectWithChildren.xml and b/xmltoolingtest/data/SimpleXMLObjectWithChildren.xml differ
index 561606c..61df325 100644 (file)
                                        >\r
                                        <Tool\r
                                                Name="VCCustomBuildTool"\r
-                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;"\r
+                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;&#x0D;&#x0A;"\r
                                                Outputs="&quot;$(InputName)&quot;.cpp"\r
                                        />\r
                                </FileConfiguration>\r
                                        >\r
                                        <Tool\r
                                                Name="VCCustomBuildTool"\r
-                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;"\r
+                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;&#x0D;&#x0A;"\r
                                                Outputs="&quot;$(InputName)&quot;.cpp"\r
                                        />\r
                                </FileConfiguration>\r
                                        >\r
                                        <Tool\r
                                                Name="VCCustomBuildTool"\r
-                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;"\r
+                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;&#x0D;&#x0A;"\r
                                                Outputs="&quot;$(InputName)&quot;.cpp"\r
                                        />\r
                                </FileConfiguration>\r
                                        >\r
                                        <Tool\r
                                                Name="VCCustomBuildTool"\r
-                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;"\r
+                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;&#x0D;&#x0A;"\r
                                                Outputs="&quot;$(InputName)&quot;.cpp"\r
                                        />\r
                                </FileConfiguration>\r
                                        >\r
                                        <Tool\r
                                                Name="VCCustomBuildTool"\r
-                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;"\r
+                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;&#x0D;&#x0A;"\r
                                                Outputs="&quot;$(InputName)&quot;.cpp"\r
                                        />\r
                                </FileConfiguration>\r
                                        >\r
                                        <Tool\r
                                                Name="VCCustomBuildTool"\r
-                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;"\r
+                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;&#x0D;&#x0A;"\r
                                                Outputs="&quot;$(InputName)&quot;.cpp"\r
                                        />\r
                                </FileConfiguration>\r