From ce200eaef5c771e132b64437d78540bfd4683572 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Mon, 18 Jan 2010 21:56:38 +0000 Subject: [PATCH] Distinguish between visibly used and unused namespaces. --- .cproject | 92 +++++++++++++++++- .../AbstractAttributeExtensibleXMLObject.cpp | 24 ++++- xmltooling/AbstractXMLObject.cpp | 21 +++-- xmltooling/AttributeExtensibleXMLObject.h | 10 +- xmltooling/Namespace.cpp | 5 +- xmltooling/Namespace.h | 21 ++++- xmltooling/io/AbstractXMLObjectUnmarshaller.cpp | 6 +- xmltoolingtest/Makefile.am | 1 + xmltoolingtest/NonVisibleNamespaceTest.h | 105 +++++++++++++++++++++ xmltoolingtest/XMLObjectBaseTestCase.h | 16 ++-- .../data/SimpleXMLObjectWithNonVisible.xml | Bin 0 -> 542 bytes 11 files changed, 272 insertions(+), 29 deletions(-) create mode 100644 xmltoolingtest/NonVisibleNamespaceTest.h create mode 100644 xmltoolingtest/data/SimpleXMLObjectWithNonVisible.xml diff --git a/.cproject b/.cproject index 23da8f4..ad088ae 100644 --- a/.cproject +++ b/.cproject @@ -57,6 +57,7 @@ + @@ -83,6 +84,9 @@ + + + @@ -165,7 +169,90 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -249,9 +336,6 @@ - - - diff --git a/xmltooling/AbstractAttributeExtensibleXMLObject.cpp b/xmltooling/AbstractAttributeExtensibleXMLObject.cpp index eae509f..44b07bc 100644 --- a/xmltooling/AbstractAttributeExtensibleXMLObject.cpp +++ b/xmltooling/AbstractAttributeExtensibleXMLObject.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2009 Internet2 + * Copyright 2001-2010 Internet2 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ using namespace xmltooling; using namespace std; +using xercesc::chColon; using xercesc::DOMAttr; using xercesc::DOMElement; @@ -137,9 +138,30 @@ void AbstractAttributeExtensibleXMLObject::setAttribute(const QName& qualifiedNa m_attributeMap[qualifiedName]=XMLString::replicate(value); if (ID) m_idAttribute = m_attributeMap.find(qualifiedName); + Namespace newNamespace(qualifiedName.getNamespaceURI(), qualifiedName.getPrefix()); + addNamespace(newNamespace); } } +void AttributeExtensibleXMLObject::setAttribute(const QName& qualifiedName, const QName& value) +{ + if (!value.hasLocalPart()) + return; + + if (value.hasPrefix()) { + xstring buf(value.getPrefix()); + buf = buf + chColon + value.getLocalPart(); + setAttribute(qualifiedName, buf.c_str()); + } + else { + setAttribute(qualifiedName, value.getLocalPart()); + } + + // Attach a non-visibly used namespace. + Namespace newNamespace(value.getNamespaceURI(), value.getPrefix(), false, false); + addNamespace(newNamespace); +} + const map& AbstractAttributeExtensibleXMLObject::getExtensionAttributes() const { return m_attributeMap; diff --git a/xmltooling/AbstractXMLObject.cpp b/xmltooling/AbstractXMLObject.cpp index 58efeda..9944a96 100644 --- a/xmltooling/AbstractXMLObject.cpp +++ b/xmltooling/AbstractXMLObject.cpp @@ -1,5 +1,5 @@ /* -* Copyright 2001-2009 Internet2 +* Copyright 2001-2010 Internet2 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,7 +60,8 @@ AbstractXMLObject::AbstractXMLObject(const XMLCh* nsURI, const XMLCh* localName, addNamespace(Namespace(nsURI, prefix)); if (schemaType) { m_typeQname = new QName(*schemaType); - addNamespace(Namespace(m_typeQname->getNamespaceURI(), m_typeQname->getPrefix())); + // Attach a non-visibly used namespace. + addNamespace(Namespace(m_typeQname->getNamespaceURI(), m_typeQname->getPrefix(), false, false)); } } @@ -133,8 +134,12 @@ void AbstractXMLObject::addNamespace(const Namespace& ns) const std::set::iterator i = m_namespaces.find(ns); if (i == m_namespaces.end()) m_namespaces.insert(ns); - else if (ns.alwaysDeclare()) - const_cast(*i).setAlwaysDeclare(true); + else { + if (ns.alwaysDeclare()) + const_cast(*i).setAlwaysDeclare(true); + if (ns.visiblyUsed()) + const_cast(*i).setVisiblyUsed(true); + } } void AbstractXMLObject::removeNamespace(const Namespace& ns) @@ -196,8 +201,8 @@ QName* AbstractXMLObject::prepareForAssignment(QName* oldValue, const QName* new if (!oldValue) { if (newValue) { releaseThisandParentDOM(); - Namespace newNamespace(newValue->getNamespaceURI(), newValue->getPrefix()); - addNamespace(newNamespace); + // Attach a non-visibly used namespace. + addNamespace(Namespace(newValue->getNamespaceURI(), newValue->getPrefix(), false, false)); return new QName(*newValue); } return NULL; @@ -206,8 +211,8 @@ QName* AbstractXMLObject::prepareForAssignment(QName* oldValue, const QName* new delete oldValue; releaseThisandParentDOM(); if (newValue) { - Namespace newNamespace(newValue->getNamespaceURI(), newValue->getPrefix()); - addNamespace(newNamespace); + // Attach a non-visibly used namespace. + addNamespace(Namespace(newValue->getNamespaceURI(), newValue->getPrefix(), false, false)); return new QName(*newValue); } return NULL; diff --git a/xmltooling/AttributeExtensibleXMLObject.h b/xmltooling/AttributeExtensibleXMLObject.h index 08eff0f..c01250f 100644 --- a/xmltooling/AttributeExtensibleXMLObject.h +++ b/xmltooling/AttributeExtensibleXMLObject.h @@ -1,5 +1,5 @@ /* - * Copyright 2001-2009 Internet2 + * Copyright 2001-2010 Internet2 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -61,6 +61,14 @@ namespace xmltooling { virtual void setAttribute(const QName& qualifiedName, const XMLCh* value, bool ID=false)=0; /** + * Sets a QName-valued XML attribute of the object. + * + * @param qualifiedName qualified name of the attribute + * @param value value to set + */ + virtual void setAttribute(const QName& qualifiedName, const QName& value); + + /** * Gets an immutable map of the extended XML attributes of the object. * * This set is not guaranteed to (and generally will not) include diff --git a/xmltooling/Namespace.cpp b/xmltooling/Namespace.cpp index ebb942f..179579b 100644 --- a/xmltooling/Namespace.cpp +++ b/xmltooling/Namespace.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2009 Internet2 + * Copyright 2001-2010 Internet2 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,7 +27,8 @@ using namespace xmltooling; using xercesc::XMLString; -Namespace::Namespace(const XMLCh* uri, const XMLCh* prefix, bool alwaysDeclare) : m_pinned(alwaysDeclare) +Namespace::Namespace(const XMLCh* uri, const XMLCh* prefix, bool alwaysDeclare, bool visiblyUsed) + : m_pinned(alwaysDeclare), m_visiblyUsed(visiblyUsed) { setNamespaceURI(uri); setNamespacePrefix(prefix); diff --git a/xmltooling/Namespace.h b/xmltooling/Namespace.h index 16ff035..8ac6382 100644 --- a/xmltooling/Namespace.h +++ b/xmltooling/Namespace.h @@ -1,5 +1,5 @@ /* - * Copyright 2001-2009 Internet2 + * Copyright 2001-2010 Internet2 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,8 +43,9 @@ namespace xmltooling { * @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 + * @param visiblyUsed true iff the namespace is visibly used by an XMLObject its attached to */ - Namespace(const XMLCh* uri=NULL, const XMLCh* prefix=NULL, bool alwaysDeclare=false); + Namespace(const XMLCh* uri=NULL, const XMLCh* prefix=NULL, bool alwaysDeclare=false, bool visiblyUsed=true); ~Namespace(); @@ -64,7 +65,13 @@ namespace xmltooling { * 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; } + const bool alwaysDeclare() const { return m_pinned; } + + /** + * Returns true iff the namespace is visibly used by an XMLObject its attached to + * @return the visiblyUsed setting + */ + const bool visiblyUsed() const { return m_visiblyUsed; } /** * Sets the namespace prefix @@ -84,8 +91,14 @@ namespace xmltooling { */ void setAlwaysDeclare(bool alwaysDeclare) { m_pinned = alwaysDeclare; } + /** + * Sets the visiblyUsed property + * @param visiblyUsed true iff the namespace is visibly used by an XMLObject its attached to + */ + void setVisiblyUsed(bool visiblyUsed) { m_visiblyUsed = visiblyUsed; } + private: - bool m_pinned; + bool m_pinned,m_visiblyUsed; xstring m_uri; xstring m_prefix; }; diff --git a/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp b/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp index b200f5b..4d0f8cc 100644 --- a/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp +++ b/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp @@ -1,5 +1,5 @@ /* -* Copyright 2001-2009 Internet2 +* Copyright 2001-2010 Internet2 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -106,14 +106,14 @@ void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domEl if (XMLString::equals(nsuri,XMLNS_NS)) { if (XMLString::equals(attribute->getLocalName(),XMLNS_PREFIX)) { m_log.debug("found default namespace declaration, adding it to the list of namespaces on the XMLObject"); - addNamespace(Namespace(attribute->getValue(), NULL, true)); + addNamespace(Namespace(attribute->getValue(), NULL, true, false)); } else if (XMLString::equals(attribute->getLocalName(),XML_PREFIX) && XMLString::equals(attribute->getNodeValue(),XML_NS)) { m_log.debug("found standard xml prefix declaration, ignoring as superfluous"); } else { m_log.debug("found namespace declaration, adding it to the list of namespaces on the XMLObject"); - addNamespace(Namespace(attribute->getValue(), attribute->getLocalName(), true)); + addNamespace(Namespace(attribute->getValue(), attribute->getLocalName(), true, false)); } continue; } diff --git a/xmltoolingtest/Makefile.am b/xmltoolingtest/Makefile.am index 5698e75..b1a5502 100644 --- a/xmltoolingtest/Makefile.am +++ b/xmltoolingtest/Makefile.am @@ -35,6 +35,7 @@ xmltoolingtest_h = \ ExceptionTest.h \ KeyInfoTest.h \ MarshallingTest.h \ + NonVisibleNamespaceTest.h \ UnmarshallingTest.h \ TemplateEngineTest.h \ xmltoolingtest.h \ diff --git a/xmltoolingtest/NonVisibleNamespaceTest.h b/xmltoolingtest/NonVisibleNamespaceTest.h new file mode 100644 index 0000000..a1eeaa7 --- /dev/null +++ b/xmltoolingtest/NonVisibleNamespaceTest.h @@ -0,0 +1,105 @@ +/* + * Copyright 2001-2010 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 NonVisibleNamespaceTest : public CxxTest::TestSuite { +public: + void setUp() { + xmltooling::QName qname(SimpleXMLObject::NAMESPACE,SimpleXMLObject::LOCAL_NAME); + xmltooling::QName qtype(SimpleXMLObject::NAMESPACE,SimpleXMLObject::TYPE_NAME); + XMLObjectBuilder::registerBuilder(qname, new SimpleXMLObjectBuilder()); + XMLObjectBuilder::registerBuilder(qtype, new SimpleXMLObjectBuilder()); + } + + void tearDown() { + xmltooling::QName qname(SimpleXMLObject::NAMESPACE,SimpleXMLObject::LOCAL_NAME); + xmltooling::QName qtype(SimpleXMLObject::NAMESPACE,SimpleXMLObject::TYPE_NAME); + XMLObjectBuilder::deregisterBuilder(qname); + XMLObjectBuilder::deregisterBuilder(qtype); + } + + void testNamespacesAfterBuilding() { + xmltooling::QName qtype(SimpleXMLObject::NAMESPACE,SimpleXMLObject::TYPE_NAME,SimpleXMLObject::NAMESPACE_PREFIX); + const XMLObjectBuilder* b = XMLObjectBuilder::getBuilder(qtype); + TS_ASSERT(b!=NULL); + auto_ptr sxObject( + dynamic_cast(b->buildObject(SimpleXMLObject::NAMESPACE, SimpleXMLObject::LOCAL_NAME, NULL, &qtype)) + ); + TS_ASSERT(sxObject.get()!=NULL); + static_cast(sxObject.get())->setAttribute( + xmltooling::QName(NULL, "attr1"), xmltooling::QName("http://www.example.org/testObjects/ext", "Value1", "test2") + ); + + static const XMLCh TEST2_PREFIX[] = { chLatin_t, chLatin_e, chLatin_s, chLatin_t, chDigit_2, chNull }; + + const set& namespaces = sxObject->getNamespaces(); + bool cond1=false, cond2=false, cond3 = false; + for (set::const_iterator ns = namespaces.begin(); ns != namespaces.end(); ++ns) { + if (XMLString::equals(ns->getNamespacePrefix(), SimpleXMLObject::NAMESPACE_PREFIX)) { + TSM_ASSERT("'test' namespace was visibly used", !ns->visiblyUsed()); + cond1 = true; + } + else if (XMLString::equals(ns->getNamespacePrefix(), TEST2_PREFIX)) { + TSM_ASSERT("'test2' namespace was visibly used", !ns->visiblyUsed()); + cond2 = true; + } + else if (XMLString::equals(ns->getNamespacePrefix(), &chNull)) { + TSM_ASSERT("Default namespace was not visibly used", ns->visiblyUsed()); + cond3 = true; + } + } + TSM_ASSERT("'test' namespace was missing.", cond1); + TSM_ASSERT("'test2' namespace was missing.", cond2); + TSM_ASSERT("Default namespace was missing.", cond3); + } + + void testNamespacesAfterUnmarshalling() { + string path=data_path + "SimpleXMLObjectWithNonVisible.xml"; + ifstream fs(path.c_str()); + DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(fs); + TS_ASSERT(doc!=NULL); + + const XMLObjectBuilder* b = XMLObjectBuilder::getBuilder(doc->getDocumentElement()); + TS_ASSERT(b!=NULL); + + auto_ptr sxObject( + dynamic_cast(b->buildFromDocument(doc)) + ); + TS_ASSERT(sxObject.get()!=NULL); + + const set& namespaces = sxObject->getNamespaces(); + bool cond1=false, cond2=false, cond3=false; + for (set::const_iterator ns = namespaces.begin(); ns != namespaces.end(); ++ns) { + if (XMLString::equals(ns->getNamespacePrefix(), SimpleXMLObject::NAMESPACE_PREFIX)) { + TSM_ASSERT("'test' namespace was visibly used", !ns->visiblyUsed()); + cond1 = true; + } + else if (XMLString::equals(ns->getNamespacePrefix(), &chNull)) { + TSM_ASSERT("Default namespace was not visibly used", ns->visiblyUsed()); + cond2 = true; + } + } + TSM_ASSERT("Default or 'test' namespace missing.", cond1 && cond2); + for (set::const_iterator ns = namespaces.begin(); ns != namespaces.end(); ++ns) { + static const XMLCh TEST2_PREFIX[] = { chLatin_t, chLatin_e, chLatin_s, chLatin_t, chDigit_2, chNull }; + TSM_ASSERT("'test2' namespace was noted during unmarshalling", !XMLString::equals(ns->getNamespacePrefix(), TEST2_PREFIX)); + } + } +}; diff --git a/xmltoolingtest/XMLObjectBaseTestCase.h b/xmltoolingtest/XMLObjectBaseTestCase.h index 99aa08f..1962683 100644 --- a/xmltoolingtest/XMLObjectBaseTestCase.h +++ b/xmltoolingtest/XMLObjectBaseTestCase.h @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Internet2 + * Copyright 2001-2010 Internet2 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ */ #include +#include #include #include #include @@ -46,14 +47,15 @@ extern string data_path; #endif class SimpleXMLObject - : public AbstractComplexElement, + : public AbstractAttributeExtensibleXMLObject, + public AbstractComplexElement, public AbstractDOMCachingXMLObject, public AbstractXMLObjectMarshaller, public AbstractXMLObjectUnmarshaller { protected: SimpleXMLObject(const SimpleXMLObject& src) - : AbstractXMLObject(src), AbstractComplexElement(src), AbstractDOMCachingXMLObject(src), + : AbstractXMLObject(src), AbstractAttributeExtensibleXMLObject(src), AbstractComplexElement(src), AbstractDOMCachingXMLObject(src), m_id(XMLString::replicate(src.m_id)) { #ifndef XMLTOOLING_NO_XMLSEC m_children.push_back(NULL); @@ -132,6 +134,7 @@ protected: domElement->setIdAttributeNS(NULL, SimpleXMLObject::ID_ATTRIB_NAME); #endif } + marshallExtensionAttributes(domElement); } void processChildElement(XMLObject* childXMLObject, const xercesc::DOMElement* root) { @@ -153,10 +156,11 @@ protected: } void processAttribute(const xercesc::DOMAttr* attribute) { - if (XMLHelper::isNodeNamed(attribute, NULL, SimpleXMLObject::ID_ATTRIB_NAME)) + if (XMLHelper::isNodeNamed(attribute, NULL, SimpleXMLObject::ID_ATTRIB_NAME)) { setId(attribute->getValue()); - else - throw UnmarshallingException("Unknown attribute cannot be processed by parent object."); + return; + } + unmarshallExtensionAttribute(attribute); } private: diff --git a/xmltoolingtest/data/SimpleXMLObjectWithNonVisible.xml b/xmltoolingtest/data/SimpleXMLObjectWithNonVisible.xml new file mode 100644 index 0000000000000000000000000000000000000000..3eea6ac1222a966de576fb1a7cb4e1cfeb3f5d27 GIT binary patch literal 542 zcmb`EO-sW-6h+UvzoNJ|X)3q~YF8En#f4Se#u~q9Vo9S-|Gau;Y%3zVk_X8!@4kEI z-uL#-0V6spX7qWbq+!7$&(s{ULq@{Df8S2c)caezHTSW5$%HYxqV~m%IHD)tg@}r| zj3vkMTgB;CmQSTxjlljuYt6|?t!1o4Y)7$WNYrf9OGTE>wVZRqljo`DMSR;AYraMO zAAgS%T?f9g&Ki~PbhY}S+{NU6*Ilw_nj1Gma~+sm$~9-4n%dMnN_`h58Zr)Eim4p(MY#usfe$^S@wvc`uk7EZT%$i7VvWxcXD<3-*~wKVMV1F#-nhX4Qo literal 0 HcmV?d00001 -- 2.1.4