From 5e67e91d34412f0f4e48088c8f6ab4e18fe5dff2 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Thu, 2 Mar 2006 21:37:07 +0000 Subject: [PATCH] Fixed inheritance hierarchy, namespace handling --- xmltooling/AbstractDOMCachingXMLObject.h | 6 +- xmltooling/AbstractXMLObject.h | 4 +- xmltooling/io/AbstractXMLObjectMarshaller.cpp | 34 ++++++++- xmltooling/io/AbstractXMLObjectUnmarshaller.cpp | 13 +++- xmltoolingtest/UnmarshallingTest.h | 81 +++++++++++++++++---- xmltoolingtest/XMLObjectBaseTestCase.h | 4 + .../data/SimpleXMLObjectWithUnknownChild.xml | Bin 0 -> 346 bytes xmltoolingtest/xmltoolingtest.h | 6 +- xmltoolingtest/xmltoolingtest.vcproj | 26 +++++++ 9 files changed, 146 insertions(+), 28 deletions(-) create mode 100644 xmltoolingtest/data/SimpleXMLObjectWithUnknownChild.xml diff --git a/xmltooling/AbstractDOMCachingXMLObject.h b/xmltooling/AbstractDOMCachingXMLObject.h index 453c634..9622d1c 100644 --- a/xmltooling/AbstractDOMCachingXMLObject.h +++ b/xmltooling/AbstractDOMCachingXMLObject.h @@ -36,7 +36,7 @@ namespace xmltooling { /** * Extension of AbstractXMLObject that implements a DOMCachingXMLObject. */ - class XMLTOOL_API AbstractDOMCachingXMLObject : public virtual AbstractXMLObject, public virtual DOMCachingXMLObject + class XMLTOOL_API AbstractDOMCachingXMLObject : public AbstractXMLObject, public DOMCachingXMLObject { public: virtual ~AbstractDOMCachingXMLObject(); @@ -132,15 +132,13 @@ namespace xmltooling { */ XMLObject* prepareForAssignment(const XMLObject* oldValue, XMLObject* newValue); - AbstractDOMCachingXMLObject() : m_dom(NULL), m_document(NULL) {} - /** * Constructor * * @param namespaceURI the namespace the element is in * @param elementLocalName the local name of the XML element this Object represents */ - AbstractDOMCachingXMLObject(const XMLCh* namespaceURI, const XMLCh* elementLocalName, const XMLCh* namespacePrefix) + AbstractDOMCachingXMLObject(const XMLCh* namespaceURI=NULL, const XMLCh* elementLocalName=NULL, const XMLCh* namespacePrefix=NULL) : AbstractXMLObject(namespaceURI,elementLocalName, namespacePrefix), m_dom(NULL), m_document(NULL) {} private: diff --git a/xmltooling/AbstractXMLObject.h b/xmltooling/AbstractXMLObject.h index 12d8408..0eeae30 100644 --- a/xmltooling/AbstractXMLObject.h +++ b/xmltooling/AbstractXMLObject.h @@ -120,15 +120,13 @@ namespace xmltooling { } protected: - AbstractXMLObject() : m_typeQname(NULL), m_parent(NULL) {} - /** * Constructor * * @param namespaceURI the namespace the element is in * @param elementLocalName the local name of the XML element this Object represents */ - AbstractXMLObject(const XMLCh* namespaceURI, const XMLCh* elementLocalName, const XMLCh* namespacePrefix) + AbstractXMLObject(const XMLCh* namespaceURI=NULL, const XMLCh* elementLocalName=NULL, const XMLCh* namespacePrefix=NULL) : m_elementQname(namespaceURI,elementLocalName, namespacePrefix), m_typeQname(NULL), m_parent(NULL) { addNamespace(Namespace(namespaceURI, namespacePrefix)); } diff --git a/xmltooling/io/AbstractXMLObjectMarshaller.cpp b/xmltooling/io/AbstractXMLObjectMarshaller.cpp index 2c0d537..65bc509 100644 --- a/xmltooling/io/AbstractXMLObjectMarshaller.cpp +++ b/xmltooling/io/AbstractXMLObjectMarshaller.cpp @@ -224,9 +224,11 @@ public: const XMLCh* uri=ns.getNamespaceURI(); // Check to see if the prefix is already declared properly above this node. - if (!ns.alwaysDeclare() && domElement->getParentNode() && - XMLString::equals(domElement->getParentNode()->lookupNamespaceURI(prefix),uri)) - return; + if (!ns.alwaysDeclare()) { + const XMLCh* declared=lookupNamespaceURI(domElement->getParentNode(),prefix); + if (declared && XMLString::equals(declared,uri)) + return; + } if (prefix && *prefix) { XMLCh* xmlns=new XMLCh[XMLString::stringLen(XMLConstants::XMLNS_PREFIX) + XMLString::stringLen(prefix) + 2*sizeof(XMLCh)]; @@ -241,6 +243,32 @@ public: domElement->setAttributeNS(XMLConstants::XMLNS_NS, XMLConstants::XMLNS_PREFIX, uri); } } + + 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) + return NULL; // we're done + DOMNamedNodeMap* attributes = static_cast(n)->getAttributes(); + if (!attributes) + return lookupNamespaceURI(n->getParentNode(),prefix); // defer to parent + DOMNode* childNode; + DOMAttr* attribute; + for (XMLSize_t i=0; igetLength(); i++) { + childNode = attributes->item(i); + if (childNode->getNodeType() != DOMNode::ATTRIBUTE_NODE) // not an attribute? + continue; + attribute = static_cast(childNode); + 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)) + return attribute->getNodeValue(); + else if (XMLString::equals(prefix,attribute->getLocalName())) + return attribute->getNodeValue(); + } + // Defer to parent. + return lookupNamespaceURI(n->getParentNode(),prefix); + } }; void AbstractXMLObjectMarshaller::marshallNamespaces(const XMLObject& xmlObject, DOMElement* domElement) const diff --git a/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp b/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp index ab69684..939311f 100644 --- a/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp +++ b/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp @@ -126,9 +126,16 @@ void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domEl const XMLCh* nsuri=attribute->getNamespaceURI(); if (XMLString::equals(nsuri,XMLConstants::XMLNS_NS)) { - XT_log.debug("found namespace declaration, adding it to the list of namespaces on the XMLObject"); - xmlObject.addNamespace(Namespace(attribute->getValue(), attribute->getLocalName(), true)); - continue; + if (XMLString::equals(attribute->getLocalName(),XMLConstants::XMLNS_PREFIX)) { + XT_log.debug("found default namespace declaration, adding it to the list of namespaces on the XMLObject"); + xmlObject.addNamespace(Namespace(attribute->getValue(), NULL, true)); + continue; + } + else { + XT_log.debug("found namespace declaration, adding it to the list of namespaces on the XMLObject"); + xmlObject.addNamespace(Namespace(attribute->getValue(), attribute->getLocalName(), true)); + continue; + } } else if (XMLString::equals(nsuri,XMLConstants::XSI_NS) && XMLString::equals(attribute->getLocalName(),type)) { XT_log.debug("found xsi:type declaration, setting the schema type of the XMLObject"); diff --git a/xmltoolingtest/UnmarshallingTest.h b/xmltoolingtest/UnmarshallingTest.h index efe505f..d4ba4f6 100644 --- a/xmltoolingtest/UnmarshallingTest.h +++ b/xmltoolingtest/UnmarshallingTest.h @@ -46,20 +46,23 @@ class UnmarshallingTest : public CxxTest::TestSuite { public: UnmarshallingTest() : m_qname(SimpleXMLObject::NAMESPACE,SimpleXMLObject::LOCAL_NAME) {} - void setUp() { - XMLObjectBuilder::registerBuilder(m_qname, new SimpleXMLObjectBuilder()); - Marshaller::registerMarshaller(m_qname, new SimpleXMLObjectMarshaller()); - Unmarshaller::registerUnmarshaller(m_qname, new SimpleXMLObjectUnmarshaller()); - } - - void tearDown() { - XMLObjectBuilder::deregisterBuilder(m_qname); - Marshaller::deregisterMarshaller(m_qname); - Unmarshaller::deregisterUnmarshaller(m_qname); - } + void setUp() { + XMLObjectBuilder::registerBuilder(m_qname, new SimpleXMLObjectBuilder()); + Marshaller::registerMarshaller(m_qname, new SimpleXMLObjectMarshaller()); + Unmarshaller::registerUnmarshaller(m_qname, new SimpleXMLObjectUnmarshaller()); + } + + void tearDown() { + XMLObjectBuilder::deregisterBuilder(m_qname); + Marshaller::deregisterMarshaller(m_qname); + Unmarshaller::deregisterUnmarshaller(m_qname); + } void testUnmarshallingWithAttributes() { - ifstream fs("../xmltoolingtest/data/SimpleXMLObjectWithAttribute.xml"); + TS_TRACE("testUnmarshallingWithAttributes"); + + string path=data_path + "SimpleXMLObjectWithAttribute.xml"; + ifstream fs(path.c_str()); DOMDocument* doc=nonvalidatingPool->parse(fs); TS_ASSERT(doc!=NULL); @@ -69,7 +72,57 @@ public: auto_ptr sxObject(dynamic_cast(u->unmarshall(doc->getDocumentElement(),true))); TS_ASSERT(sxObject.get()!=NULL); - auto_ptr_XMLCh expectedId("Firefly"); - TSM_ASSERT_SAME_DATA("ID was not expected value", expectedId.get(), sxObject->getId(), XMLString::stringLen(expectedId.get())); + auto_ptr_XMLCh expected("Firefly"); + TSM_ASSERT_SAME_DATA("ID was not expected value", expected.get(), sxObject->getId(), XMLString::stringLen(expected.get())); + } + + void testUnmarshallingWithElementContent() { + TS_TRACE("testUnmarshallingWithElementContent"); + + string path=data_path + "SimpleXMLObjectWithContent.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 sxObject(dynamic_cast(u->unmarshall(doc->getDocumentElement(),true))); + TS_ASSERT(sxObject.get()!=NULL); + + auto_ptr_XMLCh expected("Sample Content"); + TSM_ASSERT_SAME_DATA("Element content was not expected value", expected.get(), sxObject->getValue(), XMLString::stringLen(expected.get())); + } + + void testUnmarshallingWithChildElements() { + TS_TRACE("testUnmarshallingWithChildElements"); + + string path=data_path + "SimpleXMLObjectWithChildren.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 sxObject(dynamic_cast(u->unmarshall(doc->getDocumentElement(),true))); + TS_ASSERT(sxObject.get()!=NULL); + + TSM_ASSERT_EQUALS("Number of child elements was not expected value", 2, sxObject->getSimpleXMLObjects().size()); + } + + void testUnmarshallingWithUnknownChild() { + TS_TRACE("testUnmarshallingWithUnknownChild"); + + string path=data_path + "SimpleXMLObjectWithUnknownChild.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); + + TS_ASSERT_THROWS(u->unmarshall(doc->getDocumentElement(),true),UnmarshallingException); + doc->release(); } }; diff --git a/xmltoolingtest/XMLObjectBaseTestCase.h b/xmltoolingtest/XMLObjectBaseTestCase.h index d0fb2d0..ff3f3a8 100644 --- a/xmltoolingtest/XMLObjectBaseTestCase.h +++ b/xmltoolingtest/XMLObjectBaseTestCase.h @@ -29,6 +29,7 @@ using namespace std; extern ParserPool* validatingPool; extern ParserPool* nonvalidatingPool; +extern string data_path; #if defined (_MSC_VER) #pragma warning( push ) @@ -137,6 +138,9 @@ private: if (XMLString::equals(attribute->getLocalName(),SimpleXMLObject::ID_ATTRIB_NAME)) { simpleXMLObject.setId(attribute->getValue()); } + else { + throw UnmarshallingException("Unknown attribute cannot be processed by parent object."); + } } void processElementContent(XMLObject& xmlObject, const XMLCh* elementContent) const { diff --git a/xmltoolingtest/data/SimpleXMLObjectWithUnknownChild.xml b/xmltoolingtest/data/SimpleXMLObjectWithUnknownChild.xml new file mode 100644 index 0000000000000000000000000000000000000000..2e8083cc00f7aa446d0aa4349ccdb4943130fb3d GIT binary patch literal 346 zcma)%yAFad6o$Xqry%ZvE)I>tq^pDS0E)yb#Q;&BUi~deO&E+hX`7z&-_G;JjD(hg zD*<r>o%-~Ex1WLXW{O` z=`_;oJgtz%Gd_+-{Tgu$k?P?p6su+HwL;~nlp*rW6+6yCW$M&YiT}(I^^mD{yXchi OwY|(8_Urj;zxWNM_dj?5 literal 0 HcmV?d00001 diff --git a/xmltoolingtest/xmltoolingtest.h b/xmltoolingtest/xmltoolingtest.h index f3fb5af..543758d 100644 --- a/xmltoolingtest/xmltoolingtest.h +++ b/xmltoolingtest/xmltoolingtest.h @@ -24,6 +24,7 @@ using namespace xmltooling; ParserPool* validatingPool=NULL; ParserPool* nonvalidatingPool=NULL; +std::string data_path = "../xmltoolingtest/data/"; class ToolingFixture : public CxxTest::GlobalFixture { @@ -34,6 +35,8 @@ public: return false; validatingPool = new ParserPool(true,true); nonvalidatingPool = new ParserPool(); + if (getenv("XMLTOOLINGTEST_DATA")) + data_path=std::string(getenv("XMLTOOLINGTEST_DATA")) + "/"; return true; } bool tearDownWorld() { @@ -61,7 +64,8 @@ class CatalogTest : public CxxTest::TestSuite { public: void testCatalog(void) { - auto_ptr_XMLCh temp("../xmltoolingtest/data/catalog.xml"); + std::string path=data_path + "catalog.xml"; + auto_ptr_XMLCh temp(path.c_str()); TS_ASSERT(validatingPool->loadCatalog(temp.get())); } }; diff --git a/xmltoolingtest/xmltoolingtest.vcproj b/xmltoolingtest/xmltoolingtest.vcproj index 1da845b..561606c 100644 --- a/xmltoolingtest/xmltoolingtest.vcproj +++ b/xmltoolingtest/xmltoolingtest.vcproj @@ -180,6 +180,10 @@ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > + + @@ -198,6 +202,28 @@ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + + + + + + +