From e963983abe628f963602015344ad8fd65e4fe406 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Wed, 1 Mar 2006 21:18:40 +0000 Subject: [PATCH] Initial unit test plus fixes --- .cdtproject | 9 +- .gitignore | 3 + cpp-xmltooling.sln | 9 + xmltooling/AbstractDOMCachingXMLObject.cpp | 35 ++- xmltooling/AbstractDOMCachingXMLObject.h | 4 +- xmltooling/AbstractXMLObject.h | 10 +- xmltooling/Namespace.cpp | 8 +- xmltooling/Namespace.h | 20 +- xmltooling/QName.cpp | 6 +- xmltooling/QName.h | 36 +++ xmltooling/XMLObjectBuilder.cpp | 4 +- xmltooling/impl/UnknownElement.cpp | 26 +-- xmltooling/impl/UnknownElement.h | 1 + xmltooling/io/AbstractXMLObjectMarshaller.cpp | 13 +- xmltooling/io/AbstractXMLObjectUnmarshaller.cpp | 11 +- xmltooling/io/Marshaller.cpp | 6 +- xmltooling/io/Unmarshaller.cpp | 4 +- xmltooling/util/XMLHelper.cpp | 23 ++ xmltooling/util/XMLHelper.h | 11 +- xmltoolingtest/.gitignore | 4 + xmltoolingtest/UnknownTest.h | 85 +++++++ xmltoolingtest/XMLObjectBaseTestCase.h | 27 +++ .../data/SimpleXMLObjectWithChildren.xml | Bin 0 -> 344 bytes xmltoolingtest/data/catalog.xml | 7 + xmltoolingtest/xmltoolingtest.h | 67 ++++++ xmltoolingtest/xmltoolingtest.vcproj | 248 +++++++++++++++++++++ 26 files changed, 609 insertions(+), 68 deletions(-) create mode 100644 xmltoolingtest/.gitignore create mode 100644 xmltoolingtest/UnknownTest.h create mode 100644 xmltoolingtest/XMLObjectBaseTestCase.h create mode 100644 xmltoolingtest/data/SimpleXMLObjectWithChildren.xml create mode 100644 xmltoolingtest/data/catalog.xml create mode 100644 xmltoolingtest/xmltoolingtest.h create mode 100644 xmltoolingtest/xmltoolingtest.vcproj diff --git a/.cdtproject b/.cdtproject index 74757f5..ddee21c 100644 --- a/.cdtproject +++ b/.cdtproject @@ -52,12 +52,19 @@ + + - + + + + + + diff --git a/.gitignore b/.gitignore index 7dc697f..f0b5094 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,6 @@ # Simulated Subversion default ignores end here # The contents of the svn:ignore property on the branch root. /debug +/*.ncb +/*.suo +/release diff --git a/cpp-xmltooling.sln b/cpp-xmltooling.sln index 9ff2d25..dabb78b 100644 --- a/cpp-xmltooling.sln +++ b/cpp-xmltooling.sln @@ -3,6 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmltooling", "xmltooling\xmltooling.vcproj", "{06B55A46-D3B3-41AE-B5A5-B57830BA010D}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmltoolingtest", "xmltoolingtest\xmltoolingtest.vcproj", "{3E34CDCC-FCBA-490D-A165-1CB6F4559799}" + ProjectSection(ProjectDependencies) = postProject + {06B55A46-D3B3-41AE-B5A5-B57830BA010D} = {06B55A46-D3B3-41AE-B5A5-B57830BA010D} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -13,6 +18,10 @@ Global {06B55A46-D3B3-41AE-B5A5-B57830BA010D}.Debug|Win32.Build.0 = Debug|Win32 {06B55A46-D3B3-41AE-B5A5-B57830BA010D}.Release|Win32.ActiveCfg = Release|Win32 {06B55A46-D3B3-41AE-B5A5-B57830BA010D}.Release|Win32.Build.0 = Release|Win32 + {3E34CDCC-FCBA-490D-A165-1CB6F4559799}.Debug|Win32.ActiveCfg = Debug|Win32 + {3E34CDCC-FCBA-490D-A165-1CB6F4559799}.Debug|Win32.Build.0 = Debug|Win32 + {3E34CDCC-FCBA-490D-A165-1CB6F4559799}.Release|Win32.ActiveCfg = Release|Win32 + {3E34CDCC-FCBA-490D-A165-1CB6F4559799}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/xmltooling/AbstractDOMCachingXMLObject.cpp b/xmltooling/AbstractDOMCachingXMLObject.cpp index 8a23062..86f8bf7 100644 --- a/xmltooling/AbstractDOMCachingXMLObject.cpp +++ b/xmltooling/AbstractDOMCachingXMLObject.cpp @@ -57,23 +57,21 @@ void AbstractDOMCachingXMLObject::setDOM(DOMElement* dom, bool bindDocument) void AbstractDOMCachingXMLObject::releaseDOM() { Category& log=Category::getInstance(XMLTOOLING_LOGCAT".DOM"); - if (log.isDebugEnabled()) - log.debug("releasing cached DOM reprsentation for %s", getElementQName().toString().c_str()); + if (log.isDebugEnabled()) { + string qname=getElementQName().toString(); + log.debug("releasing cached DOM representation for (%s)", qname.empty() ? "unknown" : qname.c_str()); + } setDOM(NULL); } void AbstractDOMCachingXMLObject::releaseParentDOM(bool propagateRelease) { - Category& log=Category::getInstance(XMLTOOLING_LOGCAT".DOM"); - if (log.isDebugEnabled()) { - log.debug( - "releasing cached DOM representation for parent of %s with propagation set to %s", - getElementQName().toString().c_str(), propagateRelease ? "true" : "false" - ); - } - DOMCachingXMLObject* domCachingParent = dynamic_cast(getParent()); if (domCachingParent) { + Category::getInstance(XMLTOOLING_LOGCAT".DOM").debug( + "releasing cached DOM representation for parent object with propagation set to %s", + propagateRelease ? "true" : "false" + ); domCachingParent->releaseDOM(); if (propagateRelease) domCachingParent->releaseParentDOM(propagateRelease); @@ -94,23 +92,20 @@ public: void AbstractDOMCachingXMLObject::releaseChildrenDOM(bool propagateRelease) { - Category& log=Category::getInstance(XMLTOOLING_LOGCAT".DOM"); - if (log.isDebugEnabled()) { - log.debug( - "releasing cached DOM representation for children of %s with propagation set to %s", - getElementQName().toString().c_str(), propagateRelease ? "true" : "false" - ); - } - vector children; - if (getOrderedChildren(children)) + if (getOrderedChildren(children)) { + Category::getInstance(XMLTOOLING_LOGCAT".DOM").debug( + "releasing cached DOM representation for children with propagation set to %s", + propagateRelease ? "true" : "false" + ); for_each(children.begin(),children.end(),bind2nd(_release(),propagateRelease)); + } } XMLObject* AbstractDOMCachingXMLObject::prepareForAssignment(const XMLObject* oldValue, XMLObject* newValue) { if (newValue && newValue->hasParent()) - throw XMLObjectException("child XMLObject cannot be added - it is already the child of another XMLObject"); + throw XMLObjectException("Child XMLObject cannot be added - it is already the child of another XMLObject"); if (!oldValue) { if (newValue) { diff --git a/xmltooling/AbstractDOMCachingXMLObject.h b/xmltooling/AbstractDOMCachingXMLObject.h index 8093fe8..dba39e7 100644 --- a/xmltooling/AbstractDOMCachingXMLObject.h +++ b/xmltooling/AbstractDOMCachingXMLObject.h @@ -140,8 +140,8 @@ namespace xmltooling { * @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) - : AbstractXMLObject(namespaceURI,elementLocalName), m_dom(NULL), m_document(NULL) {} + AbstractDOMCachingXMLObject(const XMLCh* namespaceURI, const XMLCh* elementLocalName, const XMLCh* namespacePrefix) + : AbstractXMLObject(namespaceURI,elementLocalName, namespacePrefix), m_dom(NULL), m_document(NULL) {} private: DOMElement* m_dom; diff --git a/xmltooling/AbstractXMLObject.h b/xmltooling/AbstractXMLObject.h index a3b5a70..12d8408 100644 --- a/xmltooling/AbstractXMLObject.h +++ b/xmltooling/AbstractXMLObject.h @@ -67,7 +67,9 @@ namespace xmltooling { * @see XMLObject::addNamespace() */ void addNamespace(const Namespace& ns) { - m_namespaces.insert(ns); + if (ns.alwaysDeclare() || m_namespaces.find(ns)==m_namespaces.end()) { + m_namespaces.insert(ns); + } } /** @@ -126,8 +128,10 @@ namespace xmltooling { * @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) - : m_elementQname(namespaceURI,elementLocalName), m_typeQname(NULL), m_parent(NULL) {} + AbstractXMLObject(const XMLCh* namespaceURI, const XMLCh* elementLocalName, const XMLCh* namespacePrefix) + : m_elementQname(namespaceURI,elementLocalName, namespacePrefix), m_typeQname(NULL), m_parent(NULL) { + addNamespace(Namespace(namespaceURI, namespacePrefix)); + } private: XMLObject* m_parent; diff --git a/xmltooling/Namespace.cpp b/xmltooling/Namespace.cpp index c4bcca7..21bf4b2 100644 --- a/xmltooling/Namespace.cpp +++ b/xmltooling/Namespace.cpp @@ -25,7 +25,7 @@ using namespace xmltooling; -Namespace::Namespace(const XMLCh* uri, const XMLCh* prefix) +Namespace::Namespace(const XMLCh* uri, const XMLCh* prefix, bool alwaysDeclare) : m_pinned(alwaysDeclare) { #ifndef HAVE_GOOD_STL m_uri=m_prefix=NULL; @@ -75,19 +75,21 @@ Namespace::Namespace(const Namespace& src) { m_uri=XMLString::replicate(src.getNamespaceURI()); m_prefix=XMLString::replicate(src.getNamespacePrefix()); + m_pinned=src.getAlwaysDeclare(); } Namespace& Namespace::operator=(const Namespace& src) { m_uri=XMLString::replicate(src.getNamespaceURI()); m_prefix=XMLString::replicate(src.getNamespacePrefix()); + m_pinned=src.getAlwaysDeclare(); return *this; } bool xmltooling::operator==(const Namespace& op1, const Namespace& op2) { - return (!XMLString::compareString(op1.getNamespaceURI(),op2.getNamespaceURI()) && - !XMLString::compareString(op1.getNamespacePrefix(),op2.getNamespacePrefix())); + return (XMLString::equals(op1.getNamespaceURI(),op2.getNamespaceURI()) && + XMLString::equals(op1.getNamespacePrefix(),op2.getNamespacePrefix())); } #endif diff --git a/xmltooling/Namespace.h b/xmltooling/Namespace.h index 984df21..3e9bfc8 100644 --- a/xmltooling/Namespace.h +++ b/xmltooling/Namespace.h @@ -35,10 +35,11 @@ namespace xmltooling { public: /** * Constructor - * @param uri namespace URI - * @param prefix namespace prefix (without the colon) + * @param uri namespace URI + * @param prefix namespace prefix (without the colon) + * @param alwaysDeclare true iff the namespace should always be declared regardless of in-scope declarations */ - Namespace(const XMLCh* uri=NULL, const XMLCh* prefix=NULL); + Namespace(const XMLCh* uri=NULL, const XMLCh* prefix=NULL, bool alwaysDeclare=false); ~Namespace(); #ifndef HAVE_GOOD_STL @@ -80,6 +81,12 @@ namespace xmltooling { #endif /** + * Returns true iff the namespace should always be declared regardless of in-scope declarations + * @return the alwaysDeclared setting + */ + const bool alwaysDeclare() const { return m_pinned; } + + /** * Sets the namespace prefix * @param prefix Null-terminated Unicode string containing the prefix, without the colon */ @@ -90,8 +97,15 @@ namespace xmltooling { * @param uri Null-terminated Unicode string containing the URI */ void setNamespaceURI(const XMLCh* uri); + + /** + * Sets the alwaysDeclared property + * @param alwaysDeclare true iff the namespace should always be declared regardless of in-scope declarations + */ + void setAlwaysDeclare(bool alwaysDeclare) { m_pinned = alwaysDeclare; } private: + bool m_pinned; #ifdef HAVE_GOOD_STL xstring m_uri; xstring m_prefix; diff --git a/xmltooling/QName.cpp b/xmltooling/QName.cpp index b47588e..2c95801 100644 --- a/xmltooling/QName.cpp +++ b/xmltooling/QName.cpp @@ -123,14 +123,14 @@ bool xmltooling::operator<(const QName& op1, const QName& op2) string QName::toString() const { - if (!getLocalPart()) + if (!hasLocalPart()) return ""; auto_ptr_char local(getLocalPart()); - if (getPrefix()) { + if (hasPrefix()) { auto_ptr_char pre(getPrefix()); return string(pre.get()) + ':' + local.get(); } - else if (getNamespaceURI()) { + else if (hasNamespaceURI()) { auto_ptr_char ns(getNamespaceURI()); return string("{") + ns.get() + '}' + local.get(); } diff --git a/xmltooling/QName.h b/xmltooling/QName.h index 4df23ba..779ce70 100644 --- a/xmltooling/QName.h +++ b/xmltooling/QName.h @@ -58,6 +58,24 @@ namespace xmltooling { #ifdef HAVE_GOOD_STL /** + * Indicates whether the QName has a prefix. + * @return true iff the prefix is non-empty + */ + bool hasPrefix() const { return !m_prefix.empty(); } + + /** + * Indicates whether the QName has a non-empty namespace. + * @return true iff the namespace is non-empty + */ + bool hasNamespaceURI() const { return !m_uri.empty(); } + + /** + * Indicates whether the QName has a non-empty local name. + * @return true iff the local name is non-empty + */ + bool hasLocalPart() const { return !m_local.empty(); } + + /** * Returns the namespace prefix * @return Null-terminated Unicode string containing the prefix, without the colon */ @@ -76,6 +94,24 @@ namespace xmltooling { const XMLCh* getLocalPart() const { return m_local.c_str(); } #else /** + * Indicates whether the QName has a prefix. + * @return true iff the prefix is non-empty + */ + bool hasPrefix() const { return m_prefix && *m_prefix; } + + /** + * Indicates whether the QName has a non-empty namespace. + * @return true iff the namespace is non-empty + */ + bool hasNamespaceURI() const { return m_uri && *m_uri; } + + /** + * Indicates whether the QName has a non-empty local name. + * @return true iff the local name is non-empty + */ + bool hasLocalPart() const { return m_local && *m_local; } + + /** * Returns the namespace prefix * @return Null-terminated Unicode string containing the prefix, without the colon */ diff --git a/xmltooling/XMLObjectBuilder.cpp b/xmltooling/XMLObjectBuilder.cpp index 03b9c27..24d434d 100644 --- a/xmltooling/XMLObjectBuilder.cpp +++ b/xmltooling/XMLObjectBuilder.cpp @@ -59,7 +59,9 @@ const XMLObjectBuilder* XMLObjectBuilder::getBuilder(const DOMElement* domElemen return xmlObjectBuilder; } - log.error("no XMLObjectBuilder registered for element (%s), using default", elementName->toString().c_str()); + if (log.isDebugEnabled()) { + log.debug("no XMLObjectBuilder registered for element (%s), returning default", elementName->toString().c_str()); + } return m_default; } diff --git a/xmltooling/impl/UnknownElement.cpp b/xmltooling/impl/UnknownElement.cpp index 9af4b26..745abe9 100644 --- a/xmltooling/impl/UnknownElement.cpp +++ b/xmltooling/impl/UnknownElement.cpp @@ -24,9 +24,9 @@ #include "exceptions.h" #include "impl/UnknownElement.h" #include "util/NDC.h" +#include "util/XMLHelper.h" #include -#include #include #include #include @@ -66,25 +66,8 @@ XMLObject* UnknownElementImpl::clone() const void UnknownElementImpl::serialize(string& s) const { - if (getDOM()) { - static const XMLCh impltype[] = { chLatin_L, chLatin_S, chNull }; - static const XMLCh UTF8[]={ chLatin_U, chLatin_T, chLatin_F, chDigit_8, chNull }; - DOMImplementation* impl=DOMImplementationRegistry::getDOMImplementation(impltype); - DOMWriter* serializer=(static_cast(impl))->createDOMWriter(); - serializer->setEncoding(UTF8); - try { - MemBufFormatTarget target; - if (!serializer->writeNode(&target,*(getDOM()))) - throw XMLObjectException("unable to serialize XML to preserve DOM"); - s.erase(); - s.append(reinterpret_cast(target.getRawBuffer()),target.getLen()); - serializer->release(); - } - catch (...) { - serializer->release(); - throw; - } - } + if (getDOM()) + XMLHelper::serialize(getDOM(),s); } DOMElement* UnknownElementMarshaller::marshall(XMLObject* xmlObject, DOMDocument* document) const @@ -104,7 +87,8 @@ DOMElement* UnknownElementMarshaller::marshall(XMLObject* xmlObject, DOMDocument if (cachedDOM) { if (!document || document==cachedDOM->getOwnerDocument()) { log.debug("XMLObject has a usable cached DOM, reusing it"); - setDocumentElement(cachedDOM->getOwnerDocument(),cachedDOM); + if (document) + setDocumentElement(cachedDOM->getOwnerDocument(),cachedDOM); unk->releaseParentDOM(true); return cachedDOM; } diff --git a/xmltooling/impl/UnknownElement.h b/xmltooling/impl/UnknownElement.h index 764e17d..787cea1 100644 --- a/xmltooling/impl/UnknownElement.h +++ b/xmltooling/impl/UnknownElement.h @@ -47,6 +47,7 @@ namespace xmltooling { { public: UnknownElementImpl() {} + virtual ~UnknownElementImpl() {} /** * Overridden to ensure XML content of DOM isn't lost. diff --git a/xmltooling/io/AbstractXMLObjectMarshaller.cpp b/xmltooling/io/AbstractXMLObjectMarshaller.cpp index c66b770..0b09c3e 100644 --- a/xmltooling/io/AbstractXMLObjectMarshaller.cpp +++ b/xmltooling/io/AbstractXMLObjectMarshaller.cpp @@ -62,7 +62,8 @@ DOMElement* AbstractXMLObjectMarshaller::marshall(XMLObject* xmlObject, DOMDocum if (cachedDOM) { if (!document || document==cachedDOM->getOwnerDocument()) { XT_log.debug("XMLObject has a usable cached DOM, reusing it"); - setDocumentElement(cachedDOM->getOwnerDocument(),cachedDOM); + if (document) + setDocumentElement(cachedDOM->getOwnerDocument(),cachedDOM); dc->releaseParentDOM(true); return cachedDOM; } @@ -165,11 +166,11 @@ DOMElement* AbstractXMLObjectMarshaller::marshall(XMLObject* xmlObject, DOMEleme void AbstractXMLObjectMarshaller::marshallInto(XMLObject* xmlObject, DOMElement* targetElement) const { targetElement->setPrefix(xmlObject->getElementQName().getPrefix()); + marshallElementType(xmlObject, targetElement); marshallNamespaces(xmlObject, targetElement); marshallAttributes(xmlObject, targetElement); marshallChildElements(xmlObject, targetElement); marshallElementContent(xmlObject, targetElement); - marshallElementType(xmlObject, targetElement); /* TODO Signing/Encryption if (xmlObject instanceof SignableXMLObject) { @@ -221,6 +222,12 @@ public: void operator()(DOMElement* domElement, const Namespace& ns) const { const XMLCh* prefix=ns.getNamespacePrefix(); 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 (prefix && *prefix) { XMLCh* xmlns=new XMLCh[XMLString::stringLen(XMLConstants::XMLNS_PREFIX) + XMLString::stringLen(prefix) + 2*sizeof(XMLCh)]; *xmlns=chNull; @@ -260,7 +267,7 @@ public: ); throw MarshallingException("Marshaller found unknown child element, but no default marshaller was found."); } - element->appendChild(marshaller->marshall(obj, element->getOwnerDocument())); + element->appendChild(marshaller->marshall(obj, element)); } }; diff --git a/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp b/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp index e6bdf7e..18b09cd 100644 --- a/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp +++ b/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp @@ -121,18 +121,21 @@ void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domEl attribute = static_cast(childNode); const XMLCh* nsuri=attribute->getNamespaceURI(); - if (!XMLString::compareString(nsuri,XMLConstants::XMLNS_NS)) { + 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())); + xmlObject->addNamespace(Namespace(attribute->getValue(), attribute->getLocalName(), true)); continue; } - else if (!XMLString::compareString(nsuri,XMLConstants::XSI_NS) && - !XMLString::compareString(attribute->getLocalName(),type)) { + 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"); auto_ptr xsitype(XMLHelper::getAttributeValueAsQName(attribute)); xmlObject->setSchemaType(xsitype.get()); continue; } + else if (nsuri) { + XT_log.debug("found namespace-qualified attribute, adding prefix to the list of namespaces on the XMLObject"); + xmlObject->addNamespace(Namespace(nsuri, attribute->getPrefix())); + } XT_log.debug("processing generic attribute"); processAttribute(xmlObject, attribute); diff --git a/xmltooling/io/Marshaller.cpp b/xmltooling/io/Marshaller.cpp index 5d6a82e..2ed9d16 100644 --- a/xmltooling/io/Marshaller.cpp +++ b/xmltooling/io/Marshaller.cpp @@ -58,8 +58,10 @@ const Marshaller* Marshaller::getMarshaller(const XMLObject* xmlObject) } return m; } - - log.error("no Marshaller registered for element (%s), returning default", xmlObject->getElementQName().toString().c_str()); + if (log.isDebugEnabled()) { + string qname=xmlObject->getElementQName().toString().c_str(); + log.debug("no Marshaller registered for element (%s), returning default", qname.empty() ? "unknown" : qname.c_str()); + } return m_default; } diff --git a/xmltooling/io/Unmarshaller.cpp b/xmltooling/io/Unmarshaller.cpp index d0bba16..41acae8 100644 --- a/xmltooling/io/Unmarshaller.cpp +++ b/xmltooling/io/Unmarshaller.cpp @@ -60,7 +60,9 @@ const Unmarshaller* Unmarshaller::getUnmarshaller(const DOMElement* domElement) return m; } - log.error("no Unmarshaller registered for element (%s), using default", elementName->toString().c_str()); + if (log.isDebugEnabled()) { + log.debug("no Unmarshaller registered for element (%s), returning default", elementName->toString().c_str()); + } return m_default; } diff --git a/xmltooling/util/XMLHelper.cpp b/xmltooling/util/XMLHelper.cpp index e5962d6..d4cd911 100644 --- a/xmltooling/util/XMLHelper.cpp +++ b/xmltooling/util/XMLHelper.cpp @@ -21,9 +21,11 @@ */ #include "internal.h" +#include "exceptions.h" #include "util/XMLHelper.h" #include "util/XMLConstants.h" +#include #include using namespace xmltooling; @@ -114,3 +116,24 @@ DOMElement* XMLHelper::appendChildElement(DOMElement* parentElement, DOMElement* parentElement->appendChild(childElement); return childElement; } + +void XMLHelper::serialize(const DOMElement* e, std::string& buf) +{ + static const XMLCh impltype[] = { chLatin_L, chLatin_S, chNull }; + static const XMLCh UTF8[]={ chLatin_U, chLatin_T, chLatin_F, chDigit_8, chNull }; + DOMImplementation* impl=DOMImplementationRegistry::getDOMImplementation(impltype); + DOMWriter* serializer=(static_cast(impl))->createDOMWriter(); + serializer->setEncoding(UTF8); + try { + MemBufFormatTarget target; + if (!serializer->writeNode(&target,*e)) + throw XMLParserException("unable to serialize XML"); + buf.erase(); + buf.append(reinterpret_cast(target.getRawBuffer()),target.getLen()); + serializer->release(); + } + catch (...) { + serializer->release(); + throw; + } +} diff --git a/xmltooling/util/XMLHelper.h b/xmltooling/util/XMLHelper.h index 9cf69b9..3642029 100644 --- a/xmltooling/util/XMLHelper.h +++ b/xmltooling/util/XMLHelper.h @@ -95,8 +95,17 @@ namespace xmltooling { * @return true iff the element's qualified name matches the other parameters */ static bool isElementNamed(const DOMElement* e, const XMLCh* ns, const XMLCh* local) { - return (e && !XMLString::compareString(ns,e->getNamespaceURI()) && !XMLString::compareString(local,e->getLocalName())); + return (e && XMLString::equals(ns,e->getNamespaceURI()) && XMLString::equals(local,e->getLocalName())); } + + /** + * Serializes the DOM Element provided into a buffer using UTF-8 encoding and + * the default XML serializer available. No manipulation or formatting is applied. + * + * @param e element to serialize + * @param buf buffer to serialize element into + */ + static void serialize(const DOMElement* e, std::string& buf); }; }; diff --git a/xmltoolingtest/.gitignore b/xmltoolingtest/.gitignore new file mode 100644 index 0000000..f2fdc61 --- /dev/null +++ b/xmltoolingtest/.gitignore @@ -0,0 +1,4 @@ +/Debug +/*.user +/*.cpp +/Release diff --git a/xmltoolingtest/UnknownTest.h b/xmltoolingtest/UnknownTest.h new file mode 100644 index 0000000..46196e5 --- /dev/null +++ b/xmltoolingtest/UnknownTest.h @@ -0,0 +1,85 @@ +/* + * 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 +#include + + +class UnknownTest : public CxxTest::TestSuite { +public: + + void testUnknown() { + ifstream fs("../xmltoolingtest/data/SimpleXMLObjectWithChildren.xml"); + DOMDocument* doc=nonvalidatingPool->parse(fs); + TS_ASSERT(doc!=NULL); + + string buf1; + XMLHelper::serialize(doc->getDocumentElement(), buf1); + + const Unmarshaller* u=Unmarshaller::getUnmarshaller(doc->getDocumentElement()); + TS_ASSERT(u!=NULL); + + auto_ptr xmlObject(u->unmarshall(doc->getDocumentElement(),true)); // bind document + TS_ASSERT(xmlObject.get()!=NULL); + + auto_ptr clonedObject(xmlObject->clone()); + TS_ASSERT(clonedObject.get()!=NULL); + + const Marshaller* m=Marshaller::getMarshaller(clonedObject.get()); + TS_ASSERT(m!=NULL); + + DOMElement* rootElement=m->marshall(clonedObject.get()); + TS_ASSERT(rootElement!=NULL); + + rootElement=m->marshall(clonedObject.get()); // should reuse DOM + TS_ASSERT(rootElement!=NULL); + + string buf2; + XMLHelper::serialize(rootElement, buf2); + TS_ASSERT_EQUALS(buf1,buf2); + } + + void testUnknownWithDocChange() { + ifstream fs("../xmltoolingtest/data/SimpleXMLObjectWithChildren.xml"); + DOMDocument* doc=nonvalidatingPool->parse(fs); + TS_ASSERT(doc!=NULL); + + string buf1; + XMLHelper::serialize(doc->getDocumentElement(), buf1); + + const Unmarshaller* u=Unmarshaller::getUnmarshaller(doc->getDocumentElement()); + TS_ASSERT(u!=NULL); + + auto_ptr xmlObject(u->unmarshall(doc->getDocumentElement(),true)); // bind document + TS_ASSERT(xmlObject.get()!=NULL); + + const Marshaller* m=Marshaller::getMarshaller(xmlObject.get()); + TS_ASSERT(m!=NULL); + + DOMDocument* newDoc=nonvalidatingPool->newDocument(); + DOMElement* rootElement=m->marshall(xmlObject.get(), newDoc); + TS_ASSERT(rootElement!=NULL); + + string buf2; + XMLHelper::serialize(rootElement, buf2); + TS_ASSERT_EQUALS(buf1,buf2); + + newDoc->release(); + } +}; diff --git a/xmltoolingtest/XMLObjectBaseTestCase.h b/xmltoolingtest/XMLObjectBaseTestCase.h new file mode 100644 index 0000000..99e878a --- /dev/null +++ b/xmltoolingtest/XMLObjectBaseTestCase.h @@ -0,0 +1,27 @@ +/* + * 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 +#include +#include +#include + +using namespace xmltooling; +using namespace std; + +extern ParserPool* validatingPool; +extern ParserPool* nonvalidatingPool; + diff --git a/xmltoolingtest/data/SimpleXMLObjectWithChildren.xml b/xmltoolingtest/data/SimpleXMLObjectWithChildren.xml new file mode 100644 index 0000000000000000000000000000000000000000..ce437ed1a52a18a3791a0516b49b6d391260b6a6 GIT binary patch literal 344 zcmb7 + + + + + + diff --git a/xmltoolingtest/xmltoolingtest.h b/xmltoolingtest/xmltoolingtest.h new file mode 100644 index 0000000..f3fb5af --- /dev/null +++ b/xmltoolingtest/xmltoolingtest.h @@ -0,0 +1,67 @@ +/* + * 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 +#include + +#include +#include + +using namespace xmltooling; + +ParserPool* validatingPool=NULL; +ParserPool* nonvalidatingPool=NULL; + +class ToolingFixture : public CxxTest::GlobalFixture +{ +public: + bool setUpWorld() { + XMLToolingConfig::getConfig().log_config("DEBUG"); + if (!XMLToolingConfig::getConfig().init()) + return false; + validatingPool = new ParserPool(true,true); + nonvalidatingPool = new ParserPool(); + return true; + } + bool tearDownWorld() { + delete validatingPool; + delete nonvalidatingPool; + XMLToolingConfig::getConfig().term(); +#if defined(_MSC_VER ) && defined(XMLTOOLINGTEST_LEAKCHECK) + _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE ); + _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT ); + _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE ); + _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT ); + _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE ); + _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT ); + _CrtDumpMemoryLeaks(); +#endif + return true; + } + //bool setUp() { printf( "" ); return true; } + //bool tearDown() { printf( "" ); return true; } +}; + +static ToolingFixture globalFixture; + +class CatalogTest : public CxxTest::TestSuite +{ +public: + void testCatalog(void) { + auto_ptr_XMLCh temp("../xmltoolingtest/data/catalog.xml"); + TS_ASSERT(validatingPool->loadCatalog(temp.get())); + } +}; diff --git a/xmltoolingtest/xmltoolingtest.vcproj b/xmltoolingtest/xmltoolingtest.vcproj new file mode 100644 index 0000000..a19b4f1 --- /dev/null +++ b/xmltoolingtest/xmltoolingtest.vcproj @@ -0,0 +1,248 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- 2.1.4