Namespace handling fixes
authorScott Cantor <cantor.2@osu.edu>
Tue, 7 Mar 2006 21:06:01 +0000 (21:06 +0000)
committerScott Cantor <cantor.2@osu.edu>
Tue, 7 Mar 2006 21:06:01 +0000 (21:06 +0000)
xmltooling/AbstractXMLObject.h
xmltooling/io/AbstractXMLObjectMarshaller.cpp
xmltooling/io/AbstractXMLObjectUnmarshaller.cpp
xmltooling/util/XMLConstants.cpp
xmltooling/util/XMLConstants.h
xmltooling/util/XMLObjectChildrenList.h
xmltoolingtest/ComplexXMLObjectTest.h [new file with mode: 0644]
xmltoolingtest/Makefile.am
xmltoolingtest/XMLObjectBaseTestCase.h
xmltoolingtest/data/ComplexXMLObject.xml [new file with mode: 0644]
xmltoolingtest/xmltoolingtest.vcproj

index fd51345..9a00401 100644 (file)
@@ -153,12 +153,16 @@ namespace xmltooling {
          * Manages the lifetime of the children.\r
          */\r
         std::list<XMLObject*> m_children;\r
+\r
+        /**\r
+         * Set of namespaces associated with the object.\r
+         */\r
+        std::set<Namespace> m_namespaces;\r
         \r
     private:\r
         XMLObject* m_parent;\r
         QName m_elementQname;\r
         QName* m_typeQname;\r
-        std::set<Namespace> m_namespaces;\r
     };\r
 \r
 };\r
index da5cf65..d5c4ac0 100644 (file)
@@ -161,7 +161,8 @@ DOMElement* AbstractXMLObjectMarshaller::marshall(XMLObject* xmlObject, DOMEleme
         \r
 void AbstractXMLObjectMarshaller::marshallInto(XMLObject& xmlObject, DOMElement* targetElement) const\r
 {\r
-    targetElement->setPrefix(xmlObject.getElementQName().getPrefix());\r
+    if (xmlObject.getElementQName().hasPrefix())\r
+        targetElement->setPrefix(xmlObject.getElementQName().getPrefix());\r
     marshallElementType(xmlObject, targetElement);\r
     marshallNamespaces(xmlObject, targetElement);\r
     marshallAttributes(xmlObject, targetElement);\r
@@ -242,8 +243,12 @@ public:
 \r
     const XMLCh* lookupNamespaceURI(const DOMNode* n, const XMLCh* prefix) const {\r
         // Return NULL if no declaration in effect. The empty string signifies the null namespace.\r
-        if (!n || n->getNodeType()!=DOMNode::ELEMENT_NODE)\r
+        if (!n || n->getNodeType()!=DOMNode::ELEMENT_NODE) {\r
+            // At the root, the default namespace is set to the null namespace.\r
+            if (!prefix || !*prefix)\r
+                return &chNull;\r
             return NULL;    // we're done\r
+        }\r
         DOMNamedNodeMap* attributes = static_cast<const DOMElement*>(n)->getAttributes();\r
         if (!attributes)\r
             return lookupNamespaceURI(n->getParentNode(),prefix);   // defer to parent\r
@@ -257,7 +262,7 @@ public:
             if (!XMLString::equals(attribute->getNamespaceURI(),XMLConstants::XMLNS_NS))\r
                 continue;   // not a namespace declaration\r
             // Local name should be the prefix and the value would be the URI, except for the default namespace.\r
-            if (!prefix && XMLString::equals(attribute->getLocalName(),XMLConstants::XMLNS_PREFIX))\r
+            if ((!prefix || !*prefix) && XMLString::equals(attribute->getLocalName(),XMLConstants::XMLNS_PREFIX))\r
                 return attribute->getNodeValue();\r
             else if (XMLString::equals(prefix,attribute->getLocalName()))\r
                 return attribute->getNodeValue();\r
index 03c7293..eeb05fa 100644 (file)
@@ -48,8 +48,8 @@ XMLObject* AbstractXMLObjectUnmarshaller::unmarshall(DOMElement* element, bool b
 #endif\r
 \r
     if (XT_log.isDebugEnabled()) {\r
-        auto_ptr_char dname(element->getLocalName());\r
-        XT_log.debug("unmarshalling DOM element %s", dname.get());\r
+        auto_ptr_char dname(element->getNodeName());\r
+        XT_log.debug("unmarshalling DOM element (%s)", dname.get());\r
     }\r
 \r
     auto_ptr<XMLObject> xmlObject(buildXMLObject(element));\r
@@ -91,8 +91,8 @@ void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domEl
     static const XMLCh type[]={chLatin_t, chLatin_y, chLatin_p, chLatin_e, chNull};\r
 \r
     if (XT_log.isDebugEnabled()) {\r
-        auto_ptr_char dname(domElement->getLocalName());\r
-        XT_log.debug("unmarshalling attributes for DOM element %s", dname.get());\r
+        auto_ptr_char dname(domElement->getNodeName());\r
+        XT_log.debug("unmarshalling attributes for DOM element (%s)", dname.get());\r
     }\r
 \r
     DOMNamedNodeMap* attributes = domElement->getAttributes();\r
@@ -133,7 +133,7 @@ void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domEl
             xmlObject.setSchemaType(xsitype.get());\r
             continue;\r
         }\r
-        else if (nsuri) {\r
+        else if (nsuri && !XMLString::equals(nsuri,XMLConstants::XML_NS)) {\r
             XT_log.debug("found namespace-qualified attribute, adding prefix to the list of namespaces on the XMLObject");\r
             xmlObject.addNamespace(Namespace(nsuri, attribute->getPrefix()));\r
         }\r
@@ -150,8 +150,8 @@ void AbstractXMLObjectUnmarshaller::unmarshallChildElements(const DOMElement* do
 #endif\r
 \r
     if (XT_log.isDebugEnabled()) {\r
-        auto_ptr_char dname(domElement->getLocalName());\r
-        XT_log.debug("unmarshalling child elements of DOM element %s", dname.get());\r
+        auto_ptr_char dname(domElement->getNodeName());\r
+        XT_log.debug("unmarshalling child elements of DOM element (%s)", dname.get());\r
     }\r
 \r
     DOMNodeList* childNodes = domElement->getChildNodes();\r
@@ -170,14 +170,14 @@ void AbstractXMLObjectUnmarshaller::unmarshallChildElements(const DOMElement* do
             if (!unmarshaller) {\r
                 auto_ptr<QName> cname(XMLHelper::getNodeQName(childNode));\r
                 XT_log.error(\r
-                    "no default unmarshaller installed, found unknown child element %s", cname->toString().c_str()\r
+                    "no default unmarshaller installed, found unknown child element (%s)", cname->toString().c_str()\r
                     );\r
                 throw UnmarshallingException("Unmarshaller found unknown child element, but no default unmarshaller was found.");\r
             }\r
 \r
             if (XT_log.isDebugEnabled()) {\r
                 auto_ptr<QName> cname(XMLHelper::getNodeQName(childNode));\r
-                XT_log.debug("unmarshalling child element %s", cname->toString().c_str());\r
+                XT_log.debug("unmarshalling child element (%s)", cname->toString().c_str());\r
             }\r
 \r
             // Retain ownership of the unmarshalled child until it's processed by the parent.\r
index 2df15ed..72ab14f 100644 (file)
@@ -44,6 +44,8 @@ const XMLCh XMLConstants::XMLNS_NS[] = // http://www.w3.org/2000/xmlns/
 \r
 const XMLCh XMLConstants::XMLNS_PREFIX[] = { chLatin_x, chLatin_m, chLatin_l, chLatin_n, chLatin_s, chNull };\r
 \r
+const XMLCh XMLConstants::XML_PREFIX[] = { chLatin_x, chLatin_m, chLatin_l, chNull };\r
+\r
 const XMLCh XMLConstants::XSD_NS[] = // http://www.w3.org/2001/XMLSchema\r
 { chLatin_h, chLatin_t, chLatin_t, chLatin_p, chColon, chForwardSlash, chForwardSlash,\r
   chLatin_w, chLatin_w, chLatin_w, chPeriod, chLatin_w, chDigit_3, chPeriod, chLatin_o, chLatin_r, chLatin_g, chForwardSlash,\r
index 78b4318..a503fb7 100644 (file)
@@ -34,6 +34,9 @@ namespace xmltooling {
     {\r
         /**  XML core namespace ("http://www.w3.org/XML/1998/namespace") */\r
         static const XMLCh XML_NS[]; \r
+\r
+        /** XML namespace prefix for special xml attributes ("xml") */\r
+        static const XMLCh XML_PREFIX[];\r
     \r
         /**  XML namespace for xmlns attributes ("http://www.w3.org/2000/xmlns/") */\r
         static const XMLCh XMLNS_NS[];\r
index 18888af..dd90a19 100644 (file)
@@ -102,8 +102,7 @@ namespace xmltooling {
 
         XMLObjectChildrenIterator operator+(difference_type _Off) const {
             // return this + integer
-            XMLObjectChildrenIterator _Tmp = *this;
-            return (_Tmp += _Off);
+            return m_iter + _Off;
         }
 
         XMLObjectChildrenIterator& operator-=(difference_type _Off) {
@@ -160,7 +159,7 @@ namespace xmltooling {
 
         // We override the iterator types with our constrained wrapper.
         typedef XMLObjectChildrenIterator<Container> iterator;
-        typedef const XMLObjectChildrenIterator<Container> const_iterator;
+        typedef XMLObjectChildrenIterator<Container> const_iterator;
 
         /**
          * Constructor to expose a typed collection of children backed by a list of a base type.
diff --git a/xmltoolingtest/ComplexXMLObjectTest.h b/xmltoolingtest/ComplexXMLObjectTest.h
new file mode 100644 (file)
index 0000000..da0ecfb
--- /dev/null
@@ -0,0 +1,69 @@
+/*\r
+ *  Copyright 2001-2005 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
+#include "XMLObjectBaseTestCase.h"\r
+\r
+#include <fstream>\r
+#include <xercesc/util/XMLUniDefs.hpp>\r
+\r
+class ComplexXMLObjectTest : public CxxTest::TestSuite {\r
+public:\r
+    ComplexXMLObjectTest() {}\r
+\r
+    void setUp() {\r
+        XMLObjectBuilder::registerDefaultBuilder(new WildcardXMLObjectBuilder());\r
+        Marshaller::registerDefaultMarshaller(new WildcardXMLObjectMarshaller());\r
+        Unmarshaller::registerDefaultUnmarshaller(new WildcardXMLObjectUnmarshaller());\r
+    }\r
+\r
+    void tearDown() {\r
+        XMLObjectBuilder::deregisterDefaultBuilder();\r
+        Marshaller::deregisterDefaultMarshaller();\r
+        Unmarshaller::deregisterDefaultUnmarshaller();\r
+    }\r
+\r
+    void testComplexUnmarshalling() {\r
+        TS_TRACE("testComplexUnmarshalling");\r
+\r
+        string path=data_path + "ComplexXMLObject.xml";\r
+        ifstream fs(path.c_str());\r
+        DOMDocument* doc=nonvalidatingPool->parse(fs);\r
+        TS_ASSERT(doc!=NULL);\r
+\r
+        const Unmarshaller* u = Unmarshaller::getUnmarshaller(doc->getDocumentElement());\r
+        TS_ASSERT(u!=NULL);\r
+\r
+        auto_ptr<WildcardXMLObject> wcObject(dynamic_cast<WildcardXMLObject*>(u->unmarshall(doc->getDocumentElement(),true)));\r
+        TS_ASSERT(wcObject.get()!=NULL);\r
+\r
+        ListOf(XMLObject) kids=wcObject->getXMLObjects();\r
+        TSM_ASSERT_EQUALS("Number of child elements was not expected value", 2, kids.size());\r
+        \r
+\r
+        WildcardXMLObject* wc1=dynamic_cast<WildcardXMLObject*>(*(++kids.begin()));\r
+        WildcardXMLObject* wc2=dynamic_cast<WildcardXMLObject*>(*(++(wc1->getXMLObjects().begin())));\r
+        TSM_ASSERT_EQUALS("Number of child elements was not expected value", 3, wc2->getXMLObjects().size());\r
+\r
+        static const XMLCh html[] = {chLatin_h, chLatin_t, chLatin_m, chLatin_l, chNull};\r
+        static const XMLCh div[] = {chLatin_d, chLatin_i, chLatin_v, chNull};\r
+        auto_ptr_XMLCh htmlns("http://www.w3.org/1999/xhtml");\r
+        QName q(htmlns.get(),div,html);\r
+        ListOf(XMLObject)::const_iterator it=wc2->getXMLObjects().begin();\r
+        ++it; ++it;\r
+        TSM_ASSERT_EQUALS("Element QName unexpected", it->getElementQName(),q);\r
+    }\r
+\r
+};\r
index 1718841..c3243c9 100644 (file)
@@ -8,13 +8,14 @@ bin_PROGRAMS =
 endif
 
 xmltoolingtest_h = \
-       xmltoolingtest.h \
-       MarshallingTest.h \
-       UnknownTest.h \
-       UnmarshallingTest.h
+    ComplexXMLObjectTest.h \
+    MarshallingTest.h \
+    UnknownTest.h \
+    UnmarshallingTest.h \
+    xmltoolingtest.h
 
 noinst_HEADERS = \
-       XMLObjectBaseTestCase.h
+    XMLObjectBaseTestCase.h
 
 nodist_xmltoolingtest_SOURCES = $(xmltoolingtest_h:.h=.cpp)
 
index 68c3b3e..66f676e 100644 (file)
@@ -72,6 +72,7 @@ public:
         }
 
         ret=new SimpleXMLObject();
+        ret->m_namespaces=m_namespaces;
         ret->setId(m_id);
         ret->setValue(m_value);
         xmltooling::clone(m_children, ret->m_children);
@@ -176,9 +177,11 @@ public:
         ret=new WildcardXMLObject(
             getElementQName().getNamespaceURI(),getElementQName().getLocalPart(),getElementQName().getPrefix()
             );
+        ret->m_namespaces=m_namespaces;
         for (map<QName,XMLCh*>::const_iterator i=m_attributeMap.begin(); i!=m_attributeMap.end(); i++) {
             ret->m_attributeMap[i->first]=XMLString::replicate(i->second);
         }
+        ret->setTextContent(getTextContent());
         xmltooling::clone(m_children, ret->m_children);
         return ret;
     }
diff --git a/xmltoolingtest/data/ComplexXMLObject.xml b/xmltoolingtest/data/ComplexXMLObject.xml
new file mode 100644 (file)
index 0000000..4cb5799
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<products>
+    <product id="1144"
+        xmlns="http://example.com/product-info"
+        xmlns:html="http://www.w3.org/1999/xhtml"
+        >
+        <name xml:lang="en">Python Perfect IDE</name>
+        <description>
+            Uses mind-reading technology to anticipate and accommodate
+            all user needs in Python development.  Implements all
+            <html:code>from __future__ import</html:code> features though
+            the year 3000.  Works well with <code>1166</code>.
+        </description>
+    </product>
+    <p:product id="1166" xmlns:p="http://example.com/product-info">
+        <p:name>XSLT Perfect IDE</p:name>
+        <p:description
+            xmlns:html="http://www.w3.org/1999/xhtml"
+            xmlns:xl="http://www.w3.org/1999/xlink"
+            >
+            <p:code>red</p:code>
+            <html:code>blue</html:code>
+            <html:div>
+                <ref xl:type="simple" xl:href="index.xml">A link</ref>
+            </html:div>
+        </p:description>
+    </p:product>
+</products>
index 61df325..54abfad 100644 (file)
                        UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
                        >\r
                        <File\r
+                               RelativePath=".\ComplexXMLObjectTest.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath=".\MarshallingTest.cpp"\r
                                >\r
                        </File>\r
                        UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
                        >\r
                        <File\r
+                               RelativePath=".\ComplexXMLObjectTest.h"\r
+                               >\r
+                               <FileConfiguration\r
+                                       Name="Debug|Win32"\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
+                                               Outputs="&quot;$(InputName)&quot;.cpp"\r
+                                       />\r
+                               </FileConfiguration>\r
+                               <FileConfiguration\r
+                                       Name="Release|Win32"\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
+                                               Outputs="&quot;$(InputName)&quot;.cpp"\r
+                                       />\r
+                               </FileConfiguration>\r
+                       </File>\r
+                       <File\r
                                RelativePath=".\MarshallingTest.h"\r
                                >\r
                                <FileConfiguration\r