*/\r
\r
#include "internal.h"\r
-#include "DOMCachingXMLObject.h"\r
#include "exceptions.h"\r
#include "io/AbstractXMLObjectMarshaller.h"\r
+#ifndef XMLTOOLING_NO_XMLSEC\r
+ #include "signature/Signature.h"\r
+#endif\r
#include "util/NDC.h"\r
#include "util/XMLConstants.h"\r
#include "util/XMLHelper.h"\r
#include <xercesc/util/XMLUniDefs.hpp>\r
#include <log4cpp/Category.hh>\r
\r
+#ifndef XMLTOOLING_NO_XMLSEC\r
+ using namespace xmlsignature;\r
+#endif\r
using namespace xmltooling;\r
using namespace log4cpp;\r
using namespace std;\r
\r
#define XT_log (*static_cast<Category*>(m_log))\r
\r
-AbstractXMLObjectMarshaller::AbstractXMLObjectMarshaller(const XMLCh* targetNamespaceURI, const XMLCh* targetLocalName)\r
- : m_targetQName(targetNamespaceURI, targetLocalName),\r
- m_log(&Category::getInstance(XMLTOOLING_LOGCAT".Marshaller")) {\r
- if (!targetLocalName || !*targetLocalName)\r
- throw MarshallingException("targetLocalName cannot be null or empty");\r
-}\r
-\r
-DOMElement* AbstractXMLObjectMarshaller::marshall(XMLObject* xmlObject, DOMDocument* document) const\r
+DOMElement* AbstractXMLObjectMarshaller::marshall(\r
+ DOMDocument* document\r
+#ifndef XMLTOOLING_NO_XMLSEC\r
+ ,const std::vector<xmlsignature::Signature*>* sigs\r
+#endif\r
+ ) const\r
{\r
#ifdef _DEBUG\r
xmltooling::NDC ndc("marshall");\r
#endif\r
\r
if (XT_log.isDebugEnabled()) {\r
- XT_log.debug("starting to marshalling %s", xmlObject->getElementQName().toString().c_str());\r
+ XT_log.debug("starting to marshal %s", getElementQName().toString().c_str());\r
}\r
\r
- DOMCachingXMLObject* dc=dynamic_cast<DOMCachingXMLObject*>(xmlObject);\r
- if (dc) {\r
- DOMElement* cachedDOM=dc->getDOM();\r
- if (cachedDOM) {\r
- if (!document || document==cachedDOM->getOwnerDocument()) {\r
- XT_log.debug("XMLObject has a usable cached DOM, reusing it");\r
- if (document)\r
- setDocumentElement(cachedDOM->getOwnerDocument(),cachedDOM);\r
- dc->releaseParentDOM(true);\r
- return cachedDOM;\r
- }\r
- \r
- // We have a DOM but it doesn't match the document we were given. This both sucks and blows.\r
- // Without an adoptNode option to maintain the child pointers, we have to either import the\r
- // DOM while somehow reassigning all the nested references (which amounts to a complete\r
- // *unmarshall* operation), or we just release the existing DOM and hope that we can get\r
- // it back. This depends on all objects being able to preserve their DOM at all costs.\r
- dc->releaseChildrenDOM(true);\r
- dc->releaseDOM();\r
+ DOMElement* cachedDOM=getDOM();\r
+ if (cachedDOM) {\r
+ if (!document || document==cachedDOM->getOwnerDocument()) {\r
+ XT_log.debug("XMLObject has a usable cached DOM, reusing it");\r
+ if (document)\r
+ setDocumentElement(cachedDOM->getOwnerDocument(),cachedDOM);\r
+ releaseParentDOM(true);\r
+ return cachedDOM;\r
}\r
+ \r
+ // We have a DOM but it doesn't match the document we were given. This both sucks and blows.\r
+ // Without an adoptNode option to maintain the child pointers, we have to either import the\r
+ // DOM while somehow reassigning all the nested references (which amounts to a complete\r
+ // *unmarshall* operation), or we just release the existing DOM and hope that we can get\r
+ // it back. This depends on all objects being able to preserve their DOM at all costs.\r
+ releaseChildrenDOM(true);\r
+ releaseDOM();\r
}\r
\r
// If we get here, we didn't have a usable DOM (and/or we released the one we had).\r
document=DOMImplementationRegistry::getDOMImplementation(NULL)->createDocument();\r
bindDocument=true;\r
}\r
+ \r
+ XercesJanitor<DOMDocument> janitor(bindDocument ? document : NULL);\r
\r
- try {\r
- XT_log.debug("creating root element to marshall");\r
- DOMElement* domElement = document->createElementNS(\r
- xmlObject->getElementQName().getNamespaceURI(), xmlObject->getElementQName().getLocalPart()\r
- );\r
- setDocumentElement(document, domElement);\r
- marshallInto(*xmlObject, domElement);\r
-\r
- //Recache the DOM.\r
- if (dc) {\r
- XT_log.debug("caching DOM for XMLObject (document is %sbound)", bindDocument ? "" : "not ");\r
- dc->setDOM(domElement, bindDocument);\r
- dc->releaseParentDOM(true);\r
- }\r
+ XT_log.debug("creating root element to marshall");\r
+ DOMElement* domElement = document->createElementNS(\r
+ getElementQName().getNamespaceURI(), getElementQName().getLocalPart()\r
+ );\r
+ setDocumentElement(document, domElement);\r
+#ifndef XMLTOOLING_NO_XMLSEC\r
+ marshallInto(domElement, sigs);\r
+#else\r
+ marshallInto(domElement);\r
+#endif\r
+ //Recache the DOM.\r
+ XT_log.debug("caching DOM for XMLObject (document is %sbound)", bindDocument ? "" : "not ");\r
+ setDOM(domElement, bindDocument);\r
+ janitor.release(); // safely transferred\r
+ releaseParentDOM(true);\r
\r
- return domElement;\r
- }\r
- catch (...) {\r
- // Delete the document if need be, and rethrow.\r
- if (bindDocument) {\r
- document->release();\r
- }\r
- throw;\r
- }\r
+ return domElement;\r
}\r
\r
-DOMElement* AbstractXMLObjectMarshaller::marshall(XMLObject* xmlObject, DOMElement* parentElement) const\r
+DOMElement* AbstractXMLObjectMarshaller::marshall(\r
+ DOMElement* parentElement\r
+#ifndef XMLTOOLING_NO_XMLSEC\r
+ ,const std::vector<xmlsignature::Signature*>* sigs\r
+#endif\r
+ ) const\r
{\r
#ifdef _DEBUG\r
xmltooling::NDC ndc("marshall");\r
#endif\r
\r
if (XT_log.isDebugEnabled()) {\r
- XT_log.debug("starting to marshalling %s", xmlObject->getElementQName().toString().c_str());\r
+ XT_log.debug("starting to marshalling %s", getElementQName().toString().c_str());\r
}\r
\r
- DOMCachingXMLObject* dc=dynamic_cast<DOMCachingXMLObject*>(xmlObject);\r
- if (dc) {\r
- DOMElement* cachedDOM=dc->getDOM();\r
- if (cachedDOM) {\r
- if (parentElement->getOwnerDocument()==cachedDOM->getOwnerDocument()) {\r
- XT_log.debug("XMLObject has a usable cached DOM, reusing it");\r
- if (parentElement!=cachedDOM->getParentNode()) {\r
- parentElement->appendChild(cachedDOM);\r
- dc->releaseParentDOM(true);\r
- }\r
- return cachedDOM;\r
+ DOMElement* cachedDOM=getDOM();\r
+ if (cachedDOM) {\r
+ if (parentElement->getOwnerDocument()==cachedDOM->getOwnerDocument()) {\r
+ XT_log.debug("XMLObject has a usable cached DOM, reusing it");\r
+ if (parentElement!=cachedDOM->getParentNode()) {\r
+ parentElement->appendChild(cachedDOM);\r
+ releaseParentDOM(true);\r
}\r
- \r
- // We have a DOM but it doesn't match the document we were given. This both sucks and blows.\r
- // Without an adoptNode option to maintain the child pointers, we have to either import the\r
- // DOM while somehow reassigning all the nested references (which amounts to a complete\r
- // *unmarshall* operation), or we just release the existing DOM and hope that we can get\r
- // it back. This depends on all objects being able to preserve their DOM at all costs.\r
- dc->releaseChildrenDOM(true);\r
- dc->releaseDOM();\r
+ return cachedDOM;\r
}\r
+ \r
+ // We have a DOM but it doesn't match the document we were given. This both sucks and blows.\r
+ // Without an adoptNode option to maintain the child pointers, we have to either import the\r
+ // DOM while somehow reassigning all the nested references (which amounts to a complete\r
+ // *unmarshall* operation), or we just release the existing DOM and hope that we can get\r
+ // it back. This depends on all objects being able to preserve their DOM at all costs.\r
+ releaseChildrenDOM(true);\r
+ releaseDOM();\r
}\r
\r
// If we get here, we didn't have a usable DOM (and/or we released the one we had).\r
XT_log.debug("creating root element to marshall");\r
DOMElement* domElement = parentElement->getOwnerDocument()->createElementNS(\r
- xmlObject->getElementQName().getNamespaceURI(), xmlObject->getElementQName().getLocalPart()\r
+ getElementQName().getNamespaceURI(), getElementQName().getLocalPart()\r
);\r
parentElement->appendChild(domElement);\r
- marshallInto(*xmlObject, domElement);\r
+#ifndef XMLTOOLING_NO_XMLSEC\r
+ marshallInto(domElement, sigs);\r
+#else\r
+ marshallInto(domElement);\r
+#endif\r
\r
//Recache the DOM.\r
- if (dc) {\r
- XT_log.debug("caching DOM for XMLObject");\r
- dc->setDOM(domElement, false);\r
- dc->releaseParentDOM(true);\r
- }\r
+ XT_log.debug("caching DOM for XMLObject");\r
+ setDOM(domElement, false);\r
+ releaseParentDOM(true);\r
\r
return domElement;\r
}\r
- \r
-void AbstractXMLObjectMarshaller::marshallInto(XMLObject& xmlObject, DOMElement* targetElement) const\r
+\r
+void AbstractXMLObjectMarshaller::marshallInto(\r
+ DOMElement* targetElement\r
+#ifndef XMLTOOLING_NO_XMLSEC\r
+ ,const std::vector<xmlsignature::Signature*>* sigs\r
+#endif\r
+ ) const\r
{\r
- targetElement->setPrefix(xmlObject.getElementQName().getPrefix());\r
- marshallElementType(xmlObject, targetElement);\r
- marshallNamespaces(xmlObject, targetElement);\r
- marshallAttributes(xmlObject, targetElement);\r
- marshallChildElements(xmlObject, targetElement);\r
- marshallElementContent(xmlObject, targetElement);\r
+ if (getElementQName().hasPrefix())\r
+ targetElement->setPrefix(getElementQName().getPrefix());\r
\r
- /* TODO Signing/Encryption\r
- if (xmlObject instanceof SignableXMLObject) {\r
- signElement(targetElement, xmlObject);\r
+ if (m_schemaLocation) {\r
+ static const XMLCh schemaLocation[]= UNICODE_LITERAL_14(s,c,h,e,m,a,L,o,c,a,t,i,o,n);\r
+ if (targetElement->getParentNode()==NULL || targetElement->getParentNode()->getNodeType()==DOMNode::DOCUMENT_NODE)\r
+ targetElement->setAttributeNS(XMLConstants::XSI_NS,schemaLocation,m_schemaLocation); \r
}\r
\r
- if (xmlObject instanceof EncryptableXMLObject) {\r
- encryptElement(targetElement, xmlObject);\r
+ marshallElementType(targetElement);\r
+ marshallNamespaces(targetElement);\r
+ marshallAttributes(targetElement);\r
+ marshallContent(targetElement);\r
+ \r
+#ifndef XMLTOOLING_NO_XMLSEC\r
+ if (sigs) {\r
+ for_each(sigs->begin(),sigs->end(),mem_fun<void,Signature>(&Signature::sign));\r
}\r
- */\r
+#endif\r
}\r
\r
-void AbstractXMLObjectMarshaller::marshallElementType(XMLObject& xmlObject, DOMElement* domElement) const\r
+void AbstractXMLObjectMarshaller::marshallElementType(DOMElement* domElement) const\r
{\r
- const QName* type = xmlObject.getSchemaType();\r
+ const QName* type = getSchemaType();\r
if (type) {\r
XT_log.debug("setting xsi:type attribute for XMLObject");\r
\r
XMLString::release(&xsivalue);\r
\r
XT_log.debug("Adding XSI namespace to list of namespaces used by XMLObject");\r
- xmlObject.addNamespace(Namespace(XMLConstants::XSI_NS, XMLConstants::XSI_PREFIX));\r
+ addNamespace(Namespace(XMLConstants::XSI_NS, XMLConstants::XSI_PREFIX));\r
}\r
}\r
\r
const XMLCh* uri=ns.getNamespaceURI();\r
\r
// Check to see if the prefix is already declared properly above this node.\r
- if (!ns.alwaysDeclare() && domElement->getParentNode() &&\r
- XMLString::equals(domElement->getParentNode()->lookupNamespaceURI(prefix),uri))\r
- return;\r
+ if (!ns.alwaysDeclare()) {\r
+ const XMLCh* declared=lookupNamespaceURI(domElement->getParentNode(),prefix);\r
+ if (declared && XMLString::equals(declared,uri))\r
+ return;\r
+ }\r
\r
if (prefix && *prefix) {\r
XMLCh* xmlns=new XMLCh[XMLString::stringLen(XMLConstants::XMLNS_PREFIX) + XMLString::stringLen(prefix) + 2*sizeof(XMLCh)];\r
domElement->setAttributeNS(XMLConstants::XMLNS_NS, XMLConstants::XMLNS_PREFIX, uri);\r
}\r
}\r
-};\r
\r
-void AbstractXMLObjectMarshaller::marshallNamespaces(const XMLObject& xmlObject, DOMElement* domElement) const\r
-{\r
- XT_log.debug("marshalling namespace attributes for XMLObject");\r
- const set<Namespace>& namespaces = xmlObject.getNamespaces();\r
- for_each(namespaces.begin(),namespaces.end(),bind1st(_addns(),domElement));\r
-}\r
-\r
-class _marshallchild : public binary_function<XMLObject*,DOMElement*,void> {\r
- void* m_log;\r
-public:\r
- _marshallchild(void* log) : m_log(log) {}\r
- void operator()(XMLObject* obj, DOMElement* element) const {\r
- if (XT_log.isDebugEnabled()) {\r
- XT_log.debug("getting marshaller for child XMLObject: %s", obj->getElementQName().toString().c_str());\r
+ const XMLCh* lookupNamespaceURI(const DOMNode* n, const XMLCh* prefix) const {\r
+ // Return NULL if no declaration in effect. The empty string signifies the null namespace.\r
+ if (!n || n->getNodeType()!=DOMNode::ELEMENT_NODE) {\r
+ // At the root, the default namespace is set to the null namespace.\r
+ if (!prefix || !*prefix)\r
+ return &chNull;\r
+ return NULL; // we're done\r
}\r
-\r
- const Marshaller* marshaller = Marshaller::getMarshaller(obj);\r
- if (!marshaller) {\r
- XT_log.error(\r
- "no default unmarshaller installed, unknown child object: %s",\r
- obj->getElementQName().toString().c_str()\r
- );\r
- throw MarshallingException("Marshaller found unknown child element, but no default marshaller was found.");\r
+ DOMNamedNodeMap* attributes = static_cast<const DOMElement*>(n)->getAttributes();\r
+ if (!attributes)\r
+ return lookupNamespaceURI(n->getParentNode(),prefix); // defer to parent\r
+ DOMNode* childNode;\r
+ DOMAttr* attribute;\r
+ for (XMLSize_t i=0; i<attributes->getLength(); i++) {\r
+ childNode = attributes->item(i);\r
+ if (childNode->getNodeType() != DOMNode::ATTRIBUTE_NODE) // not an attribute?\r
+ continue;\r
+ attribute = static_cast<DOMAttr*>(childNode);\r
+ if (!XMLString::equals(attribute->getNamespaceURI(),XMLConstants::XMLNS_NS))\r
+ continue; // not a namespace declaration\r
+ // Local name should be the prefix and the value would be the URI, except for the default namespace.\r
+ if ((!prefix || !*prefix) && XMLString::equals(attribute->getLocalName(),XMLConstants::XMLNS_PREFIX))\r
+ return attribute->getNodeValue();\r
+ else if (XMLString::equals(prefix,attribute->getLocalName()))\r
+ return attribute->getNodeValue();\r
}\r
- element->appendChild(marshaller->marshall(obj, element));\r
+ // Defer to parent.\r
+ return lookupNamespaceURI(n->getParentNode(),prefix);\r
}\r
};\r
\r
-void AbstractXMLObjectMarshaller::marshallChildElements(const XMLObject& xmlObject, DOMElement* domElement) const\r
+void AbstractXMLObjectMarshaller::marshallNamespaces(DOMElement* domElement) const\r
{\r
- XT_log.debug("marshalling child elements for XMLObject");\r
+ XT_log.debug("marshalling namespace attributes for XMLObject");\r
+ const set<Namespace>& namespaces = getNamespaces();\r
+ for_each(namespaces.begin(),namespaces.end(),bind1st(_addns(),domElement));\r
+}\r
\r
- vector<XMLObject*> children;\r
- if (xmlObject.getOrderedChildren(children)) {\r
- for_each(children.begin(),children.end(),bind2nd(_marshallchild(m_log),domElement));\r
+void AbstractXMLObjectMarshaller::marshallContent(DOMElement* domElement) const\r
+{\r
+ XT_log.debug("marshalling text and child elements for XMLObject");\r
+ \r
+ const XMLCh* val;\r
+ unsigned int pos=0;\r
+ const list<XMLObject*>& children=getOrderedChildren();\r
+ for (list<XMLObject*>::const_iterator i=children.begin(); i!=children.end(); ++i, ++pos) {\r
+ val = getTextContent(pos);\r
+ if (val && *val)\r
+ domElement->appendChild(domElement->getOwnerDocument()->createTextNode(val));\r
+ if (*i)\r
+ (*i)->marshall(domElement);\r
}\r
+ val = getTextContent(pos);\r
+ if (val && *val)\r
+ domElement->appendChild(domElement->getOwnerDocument()->createTextNode(val));\r
}\r