Multi-line svn commit, see body.
authorScott Cantor <cantor.2@osu.edu>
Fri, 14 Mar 2008 01:14:23 +0000 (01:14 +0000)
committerScott Cantor <cantor.2@osu.edu>
Fri, 14 Mar 2008 01:14:23 +0000 (01:14 +0000)
Add xsi:nil support to objects.
Add basic check for nil validity to validator macros.

xmltooling/AbstractXMLObject.cpp
xmltooling/AbstractXMLObject.h
xmltooling/XMLObject.h
xmltooling/base.h
xmltooling/io/AbstractXMLObjectMarshaller.cpp
xmltooling/io/AbstractXMLObjectUnmarshaller.cpp
xmltoolingtest/data/ComplexXMLObject.xml

index 7c73f3f..6448856 100644 (file)
@@ -29,7 +29,8 @@
 using namespace xmltooling;
 
 AbstractXMLObject::AbstractXMLObject(const XMLCh* nsURI, const XMLCh* localName, const XMLCh* prefix, const QName* schemaType)
-    : m_log(logging::Category::getInstance(XMLTOOLING_LOGCAT".XMLObject")), m_schemaLocation(NULL), m_noNamespaceSchemaLocation(NULL),
+    : m_log(logging::Category::getInstance(XMLTOOLING_LOGCAT".XMLObject")),
+       m_schemaLocation(NULL), m_noNamespaceSchemaLocation(NULL), m_nil(xmlconstants::XML_BOOL_NULL),
         m_parent(NULL), m_elementQname(nsURI, localName, prefix), m_typeQname(NULL)
 {
     addNamespace(Namespace(nsURI, prefix));
@@ -41,13 +42,37 @@ AbstractXMLObject::AbstractXMLObject(const XMLCh* nsURI, const XMLCh* localName,
 
 AbstractXMLObject::AbstractXMLObject(const AbstractXMLObject& src)
     : m_namespaces(src.m_namespaces), m_log(src.m_log), m_schemaLocation(XMLString::replicate(src.m_schemaLocation)),
-        m_noNamespaceSchemaLocation(XMLString::replicate(src.m_noNamespaceSchemaLocation)),
+        m_noNamespaceSchemaLocation(XMLString::replicate(src.m_noNamespaceSchemaLocation)), m_nil(src.m_nil),
         m_parent(NULL), m_elementQname(src.m_elementQname), m_typeQname(NULL)
 {
     if (src.m_typeQname)
         m_typeQname=new QName(*src.m_typeQname);
 }
 
+void XMLObject::setNil(const XMLCh* value) {
+    if (value) {
+        switch (*value) {
+            case xercesc::chLatin_t:
+                nil(xmlconstants::XML_BOOL_TRUE);
+                break;
+            case xercesc::chLatin_f:
+                nil(xmlconstants::XML_BOOL_FALSE);
+                break;
+            case xercesc::chDigit_1:
+                nil(xmlconstants::XML_BOOL_ONE);
+                break;
+            case xercesc::chDigit_0:
+                nil(xmlconstants::XML_BOOL_ZERO);
+                break;
+            default:
+                nil(xmlconstants::XML_BOOL_NULL);
+        }
+    }
+    else {
+        nil(xmlconstants::XML_BOOL_NULL);
+    }
+}
+
 XMLCh* AbstractXMLObject::prepareForAssignment(XMLCh* oldValue, const XMLCh* newValue)
 {
     if (!XMLString::equals(oldValue,newValue)) {
index 3b41d6d..7767167 100644 (file)
@@ -79,7 +79,18 @@ namespace xmltooling {
         const XMLCh* getXMLID() const {
             return NULL;
         }
-    
+        
+        xmlconstants::xmltooling_bool_t getNil() const {
+               return m_nil;
+        }
+        
+        void nil(xmlconstants::xmltooling_bool_t value) {
+            if (m_nil != value) {
+               releaseThisandParentDOM();
+               m_nil = value;
+            }
+        }
+
         bool hasParent() const {
             return m_parent != NULL;
         }
@@ -205,6 +216,11 @@ namespace xmltooling {
          * Stores off xsi:noNamespaceSchemaLocation attribute.
          */
         XMLCh* m_noNamespaceSchemaLocation;
+        
+        /**
+         * Stores off xsi:nil attribute.
+         */
+        xmlconstants::xmltooling_bool_t m_nil;
 
     private:
         XMLObject* m_parent;
index 176a973..85f7054 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <xmltooling/QName.h>
 #include <xmltooling/Namespace.h>
+#include <xmltooling/util/XMLConstants.h>
 
 #include <set>
 #include <list>
@@ -124,6 +125,53 @@ namespace xmltooling {
          * @return an ID value or NULL 
          */
         virtual const XMLCh* getXMLID() const=0;
+
+        /**
+         * Returns the xsi:nil property of the object, or false if not set.
+         * 
+         * @return     the xsi:nil property
+         */
+        bool nil() const {
+            switch (getNil()) {
+                case xmlconstants::XML_BOOL_TRUE:
+                case xmlconstants::XML_BOOL_ONE:
+                    return true;
+                case xmlconstants::XML_BOOL_FALSE:
+                case xmlconstants::XML_BOOL_ZERO:
+                default:
+                    return false; 
+            }
+        }
+
+        /**
+         * Returns the xsi:nil property as an explicit enumerated value.
+         * 
+         * @return the xsi:nil property
+         */
+        virtual xmlconstants::xmltooling_bool_t getNil() const=0;
+        
+        /**
+         * Sets the xsi:nil property using an enumerated value.
+         * 
+         * @param value        value to set
+         */
+        virtual void nil(xmlconstants::xmltooling_bool_t value)=0;
+        
+        /**
+         * Sets the xsi:nil property.
+         * 
+         * @param value value to set
+         */
+        void nil(bool value) {
+            nil(value ? xmlconstants::XML_BOOL_ONE : xmlconstants::XML_BOOL_ZERO);
+        }
+        
+        /**
+         * Sets the xsi:nil property using a string constant.
+         * 
+         * @param value        value to set
+         */
+        void setNil(const XMLCh* value);
         
         /**
          * Checks to see if this object has a parent.
index 4936a8a..b6d3ba3 100644 (file)
         virtual void validate(const xmltooling::XMLObject* xmlObject) const { \
             const cname* ptr=dynamic_cast<const cname*>(xmlObject); \
             if (!ptr) \
-                throw xmltooling::ValidationException(#cname"SchemaValidator: unsupported object type ($1).",xmltooling::params(1,typeid(xmlObject).name()))
+                throw xmltooling::ValidationException(#cname"SchemaValidator: unsupported object type ($1).",xmltooling::params(1,typeid(xmlObject).name())); \
+            if (ptr->nil() && (ptr->hasChildren() || ptr->getTextContent())) \
+               throw xmltooling::ValidationException("Object has nil property but with children or content.")
 
 /**
  * Begins the declaration of a Schema Validator specialization subclass.
         virtual void validate(const xmltooling::XMLObject* xmlObject) const { \
             const cname* ptr=dynamic_cast<const cname*>(xmlObject); \
             if (!ptr) \
-                throw xmltooling::ValidationException(#cname"SchemaValidator: unsupported object type ($1).",xmltooling::params(1,typeid(xmlObject).name()))
+                throw xmltooling::ValidationException(#cname"SchemaValidator: unsupported object type ($1).",xmltooling::params(1,typeid(xmlObject).name()));
 
 /**
  * Ends the declaration of a Validator specialization.
index 0c87aff..622240d 100644 (file)
@@ -192,6 +192,27 @@ void AbstractXMLObjectMarshaller::marshallInto(
                 targetElement->setAttributeNS(XSI_NS,noNamespaceSchemaLocation,m_noNamespaceSchemaLocation); 
         }
     }
+    
+    static const XMLCh _nil[] = { chLatin_x, chLatin_s, chLatin_i, chColon, chLatin_n, chLatin_i, chLatin_l, chNull };
+    
+    if (m_nil != xmlconstants::XML_BOOL_NULL) {
+        switch (m_nil) {
+            case xmlconstants::XML_BOOL_TRUE:
+               targetElement->setAttributeNS(XSI_NS, _nil, xmlconstants::XML_TRUE);
+                break;
+            case xmlconstants::XML_BOOL_ONE:
+               targetElement->setAttributeNS(XSI_NS, _nil, xmlconstants::XML_ONE);
+                break;
+            case xmlconstants::XML_BOOL_FALSE:
+               targetElement->setAttributeNS(XSI_NS, _nil, xmlconstants::XML_FALSE);
+                break;
+            case xmlconstants::XML_BOOL_ZERO:
+               targetElement->setAttributeNS(XSI_NS, _nil, xmlconstants::XML_ZERO);
+                break;
+        }
+        m_log.debug("adding XSI namespace to list of namespaces used by XMLObject");
+        addNamespace(Namespace(XSI_NS, XSI_PREFIX));
+    }
 
     marshallElementType(targetElement);
     marshallNamespaces(targetElement);
index 6bc173d..5a07591 100644 (file)
@@ -111,6 +111,7 @@ void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domEl
             static const XMLCh type[]= UNICODE_LITERAL_4(t,y,p,e);
             static const XMLCh schemaLocation[]= UNICODE_LITERAL_14(s,c,h,e,m,a,L,o,c,a,t,i,o,n);
             static const XMLCh noNamespaceSchemaLocation[]= UNICODE_LITERAL_25(n,o,N,a,m,e,s,p,a,c,e,S,c,h,e,m,a,L,o,c,a,t,i,o,n);
+            static const XMLCh _nil[]= UNICODE_LITERAL_3(n,i,l);
             if (XMLString::equals(attribute->getLocalName(),type)) {
                 m_log.debug("skipping xsi:type declaration");
                 continue;
@@ -130,6 +131,11 @@ void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domEl
                 m_noNamespaceSchemaLocation=XMLString::replicate(attribute->getValue());
                 continue;
             }
+            else if (XMLString::equals(attribute->getLocalName(), _nil)) {
+               m_log.debug("processing xsi:nil attribute");
+               setNil(attribute->getValue());
+               continue;
+            }
         }
         else if (nsuri && !XMLString::equals(nsuri,XML_NS)) {
             m_log.debug("found namespace-qualified attribute, adding prefix to the list of namespaces on the XMLObject");
index 7b97ccb..f93c5d9 100644 (file)
@@ -2,6 +2,7 @@
 <products xmlns:p="http://example.com/product-info">
     <product id="1144" xmlns="http://example.com/product-info">
         <name xml:lang="en">Python Perfect IDE</name>
+        <empty xsi:nil="1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
         <description>
             Uses mind-reading technology to anticipate and accommodate
             all user needs in Python development.  Implements all