Merged marshalling/unmarshalling methods into core interface.
[shibboleth/cpp-xmltooling.git] / xmltooling / io / AbstractXMLObjectUnmarshaller.cpp
index 9aefabc..701494b 100644 (file)
@@ -21,7 +21,6 @@
  */\r
 \r
 #include "internal.h"\r
-#include "DOMCachingXMLObject.h"\r
 #include "exceptions.h"\r
 #include "XMLObjectBuilder.h"\r
 #include "io/AbstractXMLObjectUnmarshaller.h"\r
@@ -38,39 +37,22 @@ using namespace std;
 \r
 #define XT_log (*static_cast<Category*>(m_log))\r
 \r
-AbstractXMLObjectUnmarshaller::AbstractXMLObjectUnmarshaller(const XMLCh* targetNamespaceURI, const XMLCh* targetLocalName)\r
-        : m_targetQName(targetNamespaceURI, targetLocalName),\r
-        m_log(&Category::getInstance(XMLTOOLING_LOGCAT".Unmarshaller")) {\r
-    if (!targetLocalName || !*targetLocalName)\r
-        throw UnmarshallingException("targetLocalName cannot be null or empty");\r
-}\r
-\r
-XMLObject* AbstractXMLObjectUnmarshaller::unmarshall(DOMElement* element, bool bindDocument) const\r
+XMLObject* AbstractXMLObjectUnmarshaller::unmarshall(DOMElement* element, bool bindDocument)\r
 {\r
 #ifdef _DEBUG\r
     xmltooling::NDC ndc("unmarshall");\r
 #endif\r
 \r
     if (XT_log.isDebugEnabled()) {\r
-        auto_ptr_char dname(element->getLocalName());\r
-        XT_log.debug("unmarshalling DOM element %s", dname.get());\r
+        auto_ptr_char dname(element->getNodeName());\r
+        XT_log.debug("unmarshalling DOM element (%s)", dname.get());\r
     }\r
 \r
-#ifdef _DEBUG\r
-    checkElementIsTarget(element);\r
-#endif\r
-\r
-    XMLObject* xmlObject = buildXMLObject(element);\r
-\r
     if (element->hasAttributes()) {\r
-        unmarshallAttributes(element, xmlObject);\r
-    }\r
-\r
-    if (element->getTextContent()) {\r
-        processElementContent(xmlObject, element->getTextContent());\r
+        unmarshallAttributes(element);\r
     }\r
 \r
-    unmarshallChildElements(element, xmlObject);\r
+    unmarshallChildElements(element);\r
 \r
     /* TODO: Signing\r
     if (xmlObject instanceof SignableXMLObject) {\r
@@ -78,47 +60,11 @@ XMLObject* AbstractXMLObjectUnmarshaller::unmarshall(DOMElement* element, bool b
     }\r
     */\r
 \r
-    DOMCachingXMLObject* dc=dynamic_cast<DOMCachingXMLObject*>(xmlObject);\r
-    if (dc)\r
-        dc->setDOM(element,bindDocument);\r
-        \r
-    return xmlObject;\r
-}\r
-\r
-void AbstractXMLObjectUnmarshaller::checkElementIsTarget(const DOMElement* domElement) const\r
-{\r
-    auto_ptr<QName> elementName(XMLHelper::getNodeQName(domElement));\r
-\r
-    XT_log.debug("checking that root element meets target criteria");\r
-\r
-    auto_ptr<QName> type(XMLHelper::getXSIType(domElement));\r
-\r
-    if (type.get() && m_targetQName==*(type.get())) {\r
-        XT_log.debug("schema type of element matches target");\r
-        return;\r
-    }\r
-    else {\r
-        if (m_targetQName==*(elementName.get())) {\r
-            XT_log.debug("element name matches target");\r
-            return;\r
-        }\r
-        else {\r
-            XT_log.errorStream() << "unmarshaller for (" << m_targetQName.toString()\r
-                << ") passed (" << elementName->toString() << ")" << CategoryStream::ENDLINE;\r
-            throw UnmarshallingException("Incorrect element type passed to unmarshaller.");\r
-        }\r
-    }\r
-}\r
-\r
-XMLObject* AbstractXMLObjectUnmarshaller::buildXMLObject(const DOMElement* domElement) const\r
-{\r
-    const XMLObjectBuilder* xmlObjectBuilder = XMLObjectBuilder::getBuilder(domElement);\r
-    if (xmlObjectBuilder)\r
-        return xmlObjectBuilder->buildObject();\r
-    throw UnmarshallingException("Failed to locate XMLObjectBuilder for element.");\r
+    setDOM(element,bindDocument);\r
+    return this;\r
 }\r
 \r
-void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domElement, XMLObject* xmlObject) const\r
+void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domElement)\r
 {\r
 #ifdef _DEBUG\r
     xmltooling::NDC ndc("unmarshallAttributes");\r
@@ -126,8 +72,8 @@ void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domEl
     static const XMLCh type[]={chLatin_t, chLatin_y, chLatin_p, chLatin_e, chNull};\r
 \r
     if (XT_log.isDebugEnabled()) {\r
-        auto_ptr_char dname(domElement->getLocalName());\r
-        XT_log.debug("unmarshalling attributes for DOM element %s", dname.get());\r
+        auto_ptr_char dname(domElement->getNodeName());\r
+        XT_log.debug("unmarshalling attributes for DOM element (%s)", dname.get());\r
     }\r
 \r
     DOMNamedNodeMap* attributes = domElement->getAttributes();\r
@@ -150,38 +96,47 @@ void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domEl
         attribute = static_cast<DOMAttr*>(childNode);\r
         \r
         const XMLCh* nsuri=attribute->getNamespaceURI();\r
-        if (!XMLString::compareString(nsuri,XMLConstants::XMLNS_NS)) {\r
-            XT_log.debug("found namespace declaration, adding it to the list of namespaces on the XMLObject");\r
-            xmlObject->addNamespace(Namespace(attribute->getValue(), attribute->getLocalName()));\r
-            continue;\r
+        if (XMLString::equals(nsuri,XMLConstants::XMLNS_NS)) {\r
+            if (XMLString::equals(attribute->getLocalName(),XMLConstants::XMLNS_PREFIX)) {\r
+                XT_log.debug("found default namespace declaration, adding it to the list of namespaces on the XMLObject");\r
+                addNamespace(Namespace(attribute->getValue(), NULL, true));\r
+                continue;\r
+            }\r
+            else {\r
+                XT_log.debug("found namespace declaration, adding it to the list of namespaces on the XMLObject");\r
+                addNamespace(Namespace(attribute->getValue(), attribute->getLocalName(), true));\r
+                continue;\r
+            }\r
         }\r
-        else if (!XMLString::compareString(nsuri,XMLConstants::XSI_NS) &&\r
-                    !XMLString::compareString(attribute->getLocalName(),type)) {\r
+        else if (XMLString::equals(nsuri,XMLConstants::XSI_NS) && XMLString::equals(attribute->getLocalName(),type)) {\r
             XT_log.debug("found xsi:type declaration, setting the schema type of the XMLObject");\r
             auto_ptr<QName> xsitype(XMLHelper::getAttributeValueAsQName(attribute));\r
-            xmlObject->setSchemaType(xsitype.get());\r
+            setSchemaType(xsitype.get());\r
             continue;\r
         }\r
+        else if (nsuri && !XMLString::equals(nsuri,XMLConstants::XML_NS)) {\r
+            XT_log.debug("found namespace-qualified attribute, adding prefix to the list of namespaces on the XMLObject");\r
+            addNamespace(Namespace(nsuri, attribute->getPrefix()));\r
+        }\r
 \r
         XT_log.debug("processing generic attribute");\r
-        processAttribute(xmlObject, attribute);\r
+        processAttribute(attribute);\r
     }\r
 }\r
 \r
-void AbstractXMLObjectUnmarshaller::unmarshallChildElements(const DOMElement* domElement, XMLObject* xmlObject) const\r
+void AbstractXMLObjectUnmarshaller::unmarshallChildElements(const DOMElement* domElement)\r
 {\r
 #ifdef _DEBUG\r
     xmltooling::NDC ndc("unmarshallChildElements");\r
 #endif\r
 \r
     if (XT_log.isDebugEnabled()) {\r
-        auto_ptr_char dname(domElement->getLocalName());\r
-        XT_log.debug("unmarshalling child elements of DOM element %s", dname.get());\r
+        auto_ptr_char dname(domElement->getNodeName());\r
+        XT_log.debug("unmarshalling child elements of DOM element (%s)", dname.get());\r
     }\r
 \r
     DOMNodeList* childNodes = domElement->getChildNodes();\r
     DOMNode* childNode;\r
-    const Unmarshaller* unmarshaller;\r
     if (!childNodes || childNodes->getLength()==0) {\r
         XT_log.debug("element had no children");\r
         return;\r
@@ -191,31 +146,27 @@ void AbstractXMLObjectUnmarshaller::unmarshallChildElements(const DOMElement* do
     for (XMLSize_t i = 0; i < childNodes->getLength(); i++) {\r
         childNode = childNodes->item(i);\r
         if (childNode->getNodeType() == DOMNode::ELEMENT_NODE) {\r
-            unmarshaller = Unmarshaller::getUnmarshaller(static_cast<DOMElement*>(childNode));\r
-            if (!unmarshaller) {\r
-                if (config.ignoreUnknownElements) {\r
-                    unmarshaller=Unmarshaller::getDefaultUnmarshaller();\r
-                    if (!unmarshaller) {\r
-                        auto_ptr<QName> cname(XMLHelper::getNodeQName(childNode));\r
-                        XT_log.error("no default unmarshaller installed, detected unknown child element %s", cname->toString().c_str());\r
-                        throw UnmarshallingException("Unmarshaller detected unknown child element, but no default unmarshaller was found.");\r
-                    }\r
-                    else {\r
-                        XT_log.debug("using default unmarshaller");\r
-                    }\r
-                }\r
-                else {\r
-                    auto_ptr<QName> cname(XMLHelper::getNodeQName(childNode));\r
-                    XT_log.error("detected unknown child element %s", cname->toString().c_str());\r
-                    throw UnknownElementException("Unmarshaller detected unknown child element.");\r
-                }\r
+            const XMLObjectBuilder* builder = XMLObjectBuilder::getBuilder(static_cast<DOMElement*>(childNode));\r
+            if (!builder) {\r
+                auto_ptr<QName> cname(XMLHelper::getNodeQName(childNode));\r
+                XT_log.error("no default builder installed, found unknown child element (%s)", cname->toString().c_str());\r
+                throw UnmarshallingException("Unmarshaller found unknown child element, but no default builder was found.");\r
             }\r
 \r
             if (XT_log.isDebugEnabled()) {\r
                 auto_ptr<QName> cname(XMLHelper::getNodeQName(childNode));\r
-                XT_log.debug("unmarshalling child element %s", cname->toString().c_str());\r
+                XT_log.debug("unmarshalling child element (%s)", cname->toString().c_str());\r
             }\r
-            processChildElement(xmlObject, unmarshaller->unmarshall(static_cast<DOMElement*>(childNode)));\r
+\r
+            // Retain ownership of the unmarshalled child until it's processed by the parent.\r
+            auto_ptr<XMLObject> childObject(builder->buildObject(static_cast<DOMElement*>(childNode)));\r
+            childObject->unmarshall(static_cast<DOMElement*>(childNode));\r
+            processChildElement(childObject.get(), static_cast<DOMElement*>(childNode));\r
+            childObject.release();\r
+        }\r
+        else if (childNode->getNodeType() == DOMNode::TEXT_NODE) {\r
+            XT_log.debug("processing element content");\r
+            processElementContent(childNode->getNodeValue());\r
         }\r
     }\r
 }\r