From 676c0279ec7584dbb046c84ed9768c726afc009d Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Tue, 7 Mar 2006 21:06:01 +0000 Subject: [PATCH] Namespace handling fixes --- xmltooling/AbstractXMLObject.h | 6 ++- xmltooling/io/AbstractXMLObjectMarshaller.cpp | 11 ++-- xmltooling/io/AbstractXMLObjectUnmarshaller.cpp | 18 +++---- xmltooling/util/XMLConstants.cpp | 2 + xmltooling/util/XMLConstants.h | 3 ++ xmltooling/util/XMLObjectChildrenList.h | 5 +- xmltoolingtest/ComplexXMLObjectTest.h | 69 +++++++++++++++++++++++++ xmltoolingtest/Makefile.am | 11 ++-- xmltoolingtest/XMLObjectBaseTestCase.h | 3 ++ xmltoolingtest/data/ComplexXMLObject.xml | 28 ++++++++++ xmltoolingtest/xmltoolingtest.vcproj | 26 ++++++++++ 11 files changed, 161 insertions(+), 21 deletions(-) create mode 100644 xmltoolingtest/ComplexXMLObjectTest.h create mode 100644 xmltoolingtest/data/ComplexXMLObject.xml diff --git a/xmltooling/AbstractXMLObject.h b/xmltooling/AbstractXMLObject.h index fd51345..9a00401 100644 --- a/xmltooling/AbstractXMLObject.h +++ b/xmltooling/AbstractXMLObject.h @@ -153,12 +153,16 @@ namespace xmltooling { * Manages the lifetime of the children. */ std::list m_children; + + /** + * Set of namespaces associated with the object. + */ + std::set m_namespaces; private: XMLObject* m_parent; QName m_elementQname; QName* m_typeQname; - std::set m_namespaces; }; }; diff --git a/xmltooling/io/AbstractXMLObjectMarshaller.cpp b/xmltooling/io/AbstractXMLObjectMarshaller.cpp index da5cf65..d5c4ac0 100644 --- a/xmltooling/io/AbstractXMLObjectMarshaller.cpp +++ b/xmltooling/io/AbstractXMLObjectMarshaller.cpp @@ -161,7 +161,8 @@ DOMElement* AbstractXMLObjectMarshaller::marshall(XMLObject* xmlObject, DOMEleme void AbstractXMLObjectMarshaller::marshallInto(XMLObject& xmlObject, DOMElement* targetElement) const { - targetElement->setPrefix(xmlObject.getElementQName().getPrefix()); + if (xmlObject.getElementQName().hasPrefix()) + targetElement->setPrefix(xmlObject.getElementQName().getPrefix()); marshallElementType(xmlObject, targetElement); marshallNamespaces(xmlObject, targetElement); marshallAttributes(xmlObject, targetElement); @@ -242,8 +243,12 @@ public: const XMLCh* lookupNamespaceURI(const DOMNode* n, const XMLCh* prefix) const { // Return NULL if no declaration in effect. The empty string signifies the null namespace. - if (!n || n->getNodeType()!=DOMNode::ELEMENT_NODE) + if (!n || n->getNodeType()!=DOMNode::ELEMENT_NODE) { + // At the root, the default namespace is set to the null namespace. + if (!prefix || !*prefix) + return &chNull; return NULL; // we're done + } DOMNamedNodeMap* attributes = static_cast(n)->getAttributes(); if (!attributes) return lookupNamespaceURI(n->getParentNode(),prefix); // defer to parent @@ -257,7 +262,7 @@ public: if (!XMLString::equals(attribute->getNamespaceURI(),XMLConstants::XMLNS_NS)) continue; // not a namespace declaration // Local name should be the prefix and the value would be the URI, except for the default namespace. - if (!prefix && XMLString::equals(attribute->getLocalName(),XMLConstants::XMLNS_PREFIX)) + if ((!prefix || !*prefix) && XMLString::equals(attribute->getLocalName(),XMLConstants::XMLNS_PREFIX)) return attribute->getNodeValue(); else if (XMLString::equals(prefix,attribute->getLocalName())) return attribute->getNodeValue(); diff --git a/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp b/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp index 03c7293..eeb05fa 100644 --- a/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp +++ b/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp @@ -48,8 +48,8 @@ XMLObject* AbstractXMLObjectUnmarshaller::unmarshall(DOMElement* element, bool b #endif if (XT_log.isDebugEnabled()) { - auto_ptr_char dname(element->getLocalName()); - XT_log.debug("unmarshalling DOM element %s", dname.get()); + auto_ptr_char dname(element->getNodeName()); + XT_log.debug("unmarshalling DOM element (%s)", dname.get()); } auto_ptr xmlObject(buildXMLObject(element)); @@ -91,8 +91,8 @@ void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domEl static const XMLCh type[]={chLatin_t, chLatin_y, chLatin_p, chLatin_e, chNull}; if (XT_log.isDebugEnabled()) { - auto_ptr_char dname(domElement->getLocalName()); - XT_log.debug("unmarshalling attributes for DOM element %s", dname.get()); + auto_ptr_char dname(domElement->getNodeName()); + XT_log.debug("unmarshalling attributes for DOM element (%s)", dname.get()); } DOMNamedNodeMap* attributes = domElement->getAttributes(); @@ -133,7 +133,7 @@ void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domEl xmlObject.setSchemaType(xsitype.get()); continue; } - else if (nsuri) { + else if (nsuri && !XMLString::equals(nsuri,XMLConstants::XML_NS)) { XT_log.debug("found namespace-qualified attribute, adding prefix to the list of namespaces on the XMLObject"); xmlObject.addNamespace(Namespace(nsuri, attribute->getPrefix())); } @@ -150,8 +150,8 @@ void AbstractXMLObjectUnmarshaller::unmarshallChildElements(const DOMElement* do #endif if (XT_log.isDebugEnabled()) { - auto_ptr_char dname(domElement->getLocalName()); - XT_log.debug("unmarshalling child elements of DOM element %s", dname.get()); + auto_ptr_char dname(domElement->getNodeName()); + XT_log.debug("unmarshalling child elements of DOM element (%s)", dname.get()); } DOMNodeList* childNodes = domElement->getChildNodes(); @@ -170,14 +170,14 @@ void AbstractXMLObjectUnmarshaller::unmarshallChildElements(const DOMElement* do if (!unmarshaller) { auto_ptr cname(XMLHelper::getNodeQName(childNode)); XT_log.error( - "no default unmarshaller installed, found unknown child element %s", cname->toString().c_str() + "no default unmarshaller installed, found unknown child element (%s)", cname->toString().c_str() ); throw UnmarshallingException("Unmarshaller found unknown child element, but no default unmarshaller was found."); } if (XT_log.isDebugEnabled()) { auto_ptr cname(XMLHelper::getNodeQName(childNode)); - XT_log.debug("unmarshalling child element %s", cname->toString().c_str()); + XT_log.debug("unmarshalling child element (%s)", cname->toString().c_str()); } // Retain ownership of the unmarshalled child until it's processed by the parent. diff --git a/xmltooling/util/XMLConstants.cpp b/xmltooling/util/XMLConstants.cpp index 2df15ed..72ab14f 100644 --- a/xmltooling/util/XMLConstants.cpp +++ b/xmltooling/util/XMLConstants.cpp @@ -44,6 +44,8 @@ const XMLCh XMLConstants::XMLNS_NS[] = // http://www.w3.org/2000/xmlns/ const XMLCh XMLConstants::XMLNS_PREFIX[] = { chLatin_x, chLatin_m, chLatin_l, chLatin_n, chLatin_s, chNull }; +const XMLCh XMLConstants::XML_PREFIX[] = { chLatin_x, chLatin_m, chLatin_l, chNull }; + const XMLCh XMLConstants::XSD_NS[] = // http://www.w3.org/2001/XMLSchema { chLatin_h, chLatin_t, chLatin_t, chLatin_p, chColon, chForwardSlash, chForwardSlash, chLatin_w, chLatin_w, chLatin_w, chPeriod, chLatin_w, chDigit_3, chPeriod, chLatin_o, chLatin_r, chLatin_g, chForwardSlash, diff --git a/xmltooling/util/XMLConstants.h b/xmltooling/util/XMLConstants.h index 78b4318..a503fb7 100644 --- a/xmltooling/util/XMLConstants.h +++ b/xmltooling/util/XMLConstants.h @@ -34,6 +34,9 @@ namespace xmltooling { { /** XML core namespace ("http://www.w3.org/XML/1998/namespace") */ static const XMLCh XML_NS[]; + + /** XML namespace prefix for special xml attributes ("xml") */ + static const XMLCh XML_PREFIX[]; /** XML namespace for xmlns attributes ("http://www.w3.org/2000/xmlns/") */ static const XMLCh XMLNS_NS[]; diff --git a/xmltooling/util/XMLObjectChildrenList.h b/xmltooling/util/XMLObjectChildrenList.h index 18888af..dd90a19 100644 --- a/xmltooling/util/XMLObjectChildrenList.h +++ b/xmltooling/util/XMLObjectChildrenList.h @@ -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 iterator; - typedef const XMLObjectChildrenIterator const_iterator; + typedef XMLObjectChildrenIterator 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 index 0000000..da0ecfb --- /dev/null +++ b/xmltoolingtest/ComplexXMLObjectTest.h @@ -0,0 +1,69 @@ +/* + * Copyright 2001-2005 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "XMLObjectBaseTestCase.h" + +#include +#include + +class ComplexXMLObjectTest : public CxxTest::TestSuite { +public: + ComplexXMLObjectTest() {} + + void setUp() { + XMLObjectBuilder::registerDefaultBuilder(new WildcardXMLObjectBuilder()); + Marshaller::registerDefaultMarshaller(new WildcardXMLObjectMarshaller()); + Unmarshaller::registerDefaultUnmarshaller(new WildcardXMLObjectUnmarshaller()); + } + + void tearDown() { + XMLObjectBuilder::deregisterDefaultBuilder(); + Marshaller::deregisterDefaultMarshaller(); + Unmarshaller::deregisterDefaultUnmarshaller(); + } + + void testComplexUnmarshalling() { + TS_TRACE("testComplexUnmarshalling"); + + string path=data_path + "ComplexXMLObject.xml"; + ifstream fs(path.c_str()); + DOMDocument* doc=nonvalidatingPool->parse(fs); + TS_ASSERT(doc!=NULL); + + const Unmarshaller* u = Unmarshaller::getUnmarshaller(doc->getDocumentElement()); + TS_ASSERT(u!=NULL); + + auto_ptr wcObject(dynamic_cast(u->unmarshall(doc->getDocumentElement(),true))); + TS_ASSERT(wcObject.get()!=NULL); + + ListOf(XMLObject) kids=wcObject->getXMLObjects(); + TSM_ASSERT_EQUALS("Number of child elements was not expected value", 2, kids.size()); + + + WildcardXMLObject* wc1=dynamic_cast(*(++kids.begin())); + WildcardXMLObject* wc2=dynamic_cast(*(++(wc1->getXMLObjects().begin()))); + TSM_ASSERT_EQUALS("Number of child elements was not expected value", 3, wc2->getXMLObjects().size()); + + static const XMLCh html[] = {chLatin_h, chLatin_t, chLatin_m, chLatin_l, chNull}; + static const XMLCh div[] = {chLatin_d, chLatin_i, chLatin_v, chNull}; + auto_ptr_XMLCh htmlns("http://www.w3.org/1999/xhtml"); + QName q(htmlns.get(),div,html); + ListOf(XMLObject)::const_iterator it=wc2->getXMLObjects().begin(); + ++it; ++it; + TSM_ASSERT_EQUALS("Element QName unexpected", it->getElementQName(),q); + } + +}; diff --git a/xmltoolingtest/Makefile.am b/xmltoolingtest/Makefile.am index 1718841..c3243c9 100644 --- a/xmltoolingtest/Makefile.am +++ b/xmltoolingtest/Makefile.am @@ -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) diff --git a/xmltoolingtest/XMLObjectBaseTestCase.h b/xmltoolingtest/XMLObjectBaseTestCase.h index 68c3b3e..66f676e 100644 --- a/xmltoolingtest/XMLObjectBaseTestCase.h +++ b/xmltoolingtest/XMLObjectBaseTestCase.h @@ -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::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 index 0000000..4cb5799 --- /dev/null +++ b/xmltoolingtest/data/ComplexXMLObject.xml @@ -0,0 +1,28 @@ + + + + Python Perfect IDE + + Uses mind-reading technology to anticipate and accommodate + all user needs in Python development. Implements all + from __future__ import features though + the year 3000. Works well with 1166. + + + + XSLT Perfect IDE + + red + blue + + A link + + + + diff --git a/xmltoolingtest/xmltoolingtest.vcproj b/xmltoolingtest/xmltoolingtest.vcproj index 61df325..54abfad 100644 --- a/xmltoolingtest/xmltoolingtest.vcproj +++ b/xmltoolingtest/xmltoolingtest.vcproj @@ -180,6 +180,10 @@ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > + + @@ -202,6 +206,28 @@ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + + + + + + +