\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
+AbstractXMLObjectMarshaller::AbstractXMLObjectMarshaller()\r
+ : m_log(&Category::getInstance(XMLTOOLING_LOGCAT".Marshaller")) {}\r
\r
DOMElement* AbstractXMLObjectMarshaller::marshall(XMLObject* xmlObject, DOMDocument* document) const\r
{\r
if (cachedDOM) {\r
if (!document || document==cachedDOM->getOwnerDocument()) {\r
XT_log.debug("XMLObject has a usable cached DOM, reusing it");\r
- setDocumentElement(cachedDOM->getOwnerDocument(),cachedDOM);\r
+ if (document)\r
+ setDocumentElement(cachedDOM->getOwnerDocument(),cachedDOM);\r
dc->releaseParentDOM(true);\r
return cachedDOM;\r
}\r
xmlObject->getElementQName().getNamespaceURI(), xmlObject->getElementQName().getLocalPart()\r
);\r
setDocumentElement(document, domElement);\r
- marshallInto(xmlObject, domElement);\r
+ marshallInto(*xmlObject, domElement);\r
\r
//Recache the DOM.\r
if (dc) {\r
xmlObject->getElementQName().getNamespaceURI(), xmlObject->getElementQName().getLocalPart()\r
);\r
parentElement->appendChild(domElement);\r
- marshallInto(xmlObject, domElement);\r
+ marshallInto(*xmlObject, domElement);\r
\r
//Recache the DOM.\r
if (dc) {\r
return domElement;\r
}\r
\r
-void AbstractXMLObjectMarshaller::marshallInto(XMLObject* xmlObject, DOMElement* targetElement) const\r
+void AbstractXMLObjectMarshaller::marshallInto(XMLObject& xmlObject, DOMElement* targetElement) const\r
{\r
- targetElement->setPrefix(xmlObject->getElementQName().getPrefix());\r
+ if (xmlObject.getElementQName().hasPrefix())\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
- marshallElementType(xmlObject, targetElement);\r
\r
/* TODO Signing/Encryption\r
if (xmlObject instanceof SignableXMLObject) {\r
*/\r
}\r
\r
-void AbstractXMLObjectMarshaller::marshallElementType(XMLObject* xmlObject, DOMElement* domElement) const\r
+void AbstractXMLObjectMarshaller::marshallElementType(XMLObject& xmlObject, DOMElement* domElement) const\r
{\r
- const QName* type = xmlObject->getSchemaType();\r
+ const QName* type = xmlObject.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
+ xmlObject.addNamespace(Namespace(XMLConstants::XSI_NS, XMLConstants::XSI_PREFIX));\r
}\r
}\r
\r
void operator()(DOMElement* domElement, const Namespace& ns) const {\r
const XMLCh* prefix=ns.getNamespacePrefix();\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()) {\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
*xmlns=chNull;\r
domElement->setAttributeNS(XMLConstants::XMLNS_NS, XMLConstants::XMLNS_PREFIX, uri);\r
}\r
}\r
+\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
+ 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
+ // Defer to parent.\r
+ return lookupNamespaceURI(n->getParentNode(),prefix);\r
+ }\r
};\r
\r
-void AbstractXMLObjectMarshaller::marshallNamespaces(const XMLObject* xmlObject, DOMElement* domElement) const\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
+ const set<Namespace>& namespaces = xmlObject.getNamespaces();\r
for_each(namespaces.begin(),namespaces.end(),bind1st(_addns(),domElement));\r
}\r
\r
public:\r
_marshallchild(void* log) : m_log(log) {}\r
void operator()(XMLObject* obj, DOMElement* element) const {\r
+ if (!obj)\r
+ return;\r
if (XT_log.isDebugEnabled()) {\r
XT_log.debug("getting marshaller for child XMLObject: %s", obj->getElementQName().toString().c_str());\r
}\r
);\r
throw MarshallingException("Marshaller found unknown child element, but no default marshaller was found.");\r
}\r
- element->appendChild(marshaller->marshall(obj, element->getOwnerDocument()));\r
+ element->appendChild(marshaller->marshall(obj, element));\r
}\r
};\r
\r
-void AbstractXMLObjectMarshaller::marshallChildElements(const XMLObject* xmlObject, DOMElement* domElement) const\r
+void AbstractXMLObjectMarshaller::marshallChildElements(const XMLObject& xmlObject, DOMElement* domElement) const\r
{\r
XT_log.debug("marshalling child elements for XMLObject");\r
\r
- vector<XMLObject*> children;\r
- if (xmlObject->getOrderedChildren(children)) {\r
- for_each(children.begin(),children.end(),bind2nd(_marshallchild(m_log),domElement));\r
- }\r
+ const list<XMLObject*>& children=xmlObject.getOrderedChildren();\r
+ for_each(children.begin(),children.end(),bind2nd(_marshallchild(m_log),domElement));\r
}\r