2 * Copyright 2001-2006 Internet2
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * AbstractXMLObjectUnmarshaller.cpp
20 * A thread-safe abstract unmarshaller.
24 #include "exceptions.h"
25 #include "XMLObjectBuilder.h"
26 #include "io/AbstractXMLObjectUnmarshaller.h"
28 #include "util/XMLConstants.h"
29 #include "util/XMLHelper.h"
31 #include <xercesc/util/XMLUniDefs.hpp>
32 #include <log4cpp/Category.hh>
34 using namespace xmltooling;
35 using namespace log4cpp;
38 #define XT_log (*static_cast<Category*>(m_log))
40 XMLObject* AbstractXMLObjectUnmarshaller::unmarshall(DOMElement* element, bool bindDocument)
43 xmltooling::NDC ndc("unmarshall");
46 if (getDOM() || hasParent())
47 throw UnmarshallingException("Object already contains data, it cannot be unmarshalled at this stage.");
49 if (!XMLString::equals(element->getNamespaceURI(),getElementQName().getNamespaceURI()) ||
50 !XMLString::equals(element->getLocalName(),getElementQName().getLocalPart())) {
51 throw UnmarshallingException("Unrecognized element supplied to implementation for unmarshalling.");
54 if (XT_log.isDebugEnabled()) {
55 auto_ptr_char dname(element->getNodeName());
56 XT_log.debug("unmarshalling DOM element (%s)", dname.get());
59 if (element->hasAttributes()) {
60 unmarshallAttributes(element);
63 unmarshallChildElements(element);
66 if (xmlObject instanceof SignableXMLObject) {
67 verifySignature(domElement, xmlObject);
71 setDOM(element,bindDocument);
75 void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domElement)
78 xmltooling::NDC ndc("unmarshallAttributes");
80 static const XMLCh type[]={chLatin_t, chLatin_y, chLatin_p, chLatin_e, chNull};
82 if (XT_log.isDebugEnabled()) {
83 auto_ptr_char dname(domElement->getNodeName());
84 XT_log.debug("unmarshalling attributes for DOM element (%s)", dname.get());
87 DOMNamedNodeMap* attributes = domElement->getAttributes();
89 XT_log.debug("no attributes to unmarshall");
95 for (XMLSize_t i=0; i<attributes->getLength(); i++) {
96 childNode = attributes->item(i);
98 // The child node should always be an attribute, but just in case
99 if (childNode->getNodeType() != DOMNode::ATTRIBUTE_NODE) {
100 XT_log.debug("encountered child node of type %d in attribute list, ignoring it", childNode->getNodeType());
104 attribute = static_cast<DOMAttr*>(childNode);
106 const XMLCh* nsuri=attribute->getNamespaceURI();
107 if (XMLString::equals(nsuri,XMLConstants::XMLNS_NS)) {
108 if (XMLString::equals(attribute->getLocalName(),XMLConstants::XMLNS_PREFIX)) {
109 XT_log.debug("found default namespace declaration, adding it to the list of namespaces on the XMLObject");
110 addNamespace(Namespace(attribute->getValue(), NULL, true));
114 XT_log.debug("found namespace declaration, adding it to the list of namespaces on the XMLObject");
115 addNamespace(Namespace(attribute->getValue(), attribute->getLocalName(), true));
119 else if (XMLString::equals(nsuri,XMLConstants::XSI_NS) && XMLString::equals(attribute->getLocalName(),type)) {
120 XT_log.debug("skipping xsi:type declaration");
123 else if (nsuri && !XMLString::equals(nsuri,XMLConstants::XML_NS)) {
124 XT_log.debug("found namespace-qualified attribute, adding prefix to the list of namespaces on the XMLObject");
125 addNamespace(Namespace(nsuri, attribute->getPrefix()));
128 XT_log.debug("processing generic attribute");
129 processAttribute(attribute);
133 void AbstractXMLObjectUnmarshaller::unmarshallChildElements(const DOMElement* domElement)
136 xmltooling::NDC ndc("unmarshallChildElements");
139 if (XT_log.isDebugEnabled()) {
140 auto_ptr_char dname(domElement->getNodeName());
141 XT_log.debug("unmarshalling child elements of DOM element (%s)", dname.get());
144 DOMNodeList* childNodes = domElement->getChildNodes();
146 if (!childNodes || childNodes->getLength()==0) {
147 XT_log.debug("element had no children");
151 for (XMLSize_t i = 0; i < childNodes->getLength(); i++) {
152 childNode = childNodes->item(i);
153 if (childNode->getNodeType() == DOMNode::ELEMENT_NODE) {
154 const XMLObjectBuilder* builder = XMLObjectBuilder::getBuilder(static_cast<DOMElement*>(childNode));
156 auto_ptr<QName> cname(XMLHelper::getNodeQName(childNode));
157 XT_log.error("no default builder installed, found unknown child element (%s)", cname->toString().c_str());
158 throw UnmarshallingException("Unmarshaller found unknown child element, but no default builder was found.");
161 if (XT_log.isDebugEnabled()) {
162 auto_ptr<QName> cname(XMLHelper::getNodeQName(childNode));
163 XT_log.debug("unmarshalling child element (%s)", cname->toString().c_str());
166 // Retain ownership of the unmarshalled child until it's processed by the parent.
167 auto_ptr<XMLObject> childObject(builder->buildFromElement(static_cast<DOMElement*>(childNode)));
168 processChildElement(childObject.get(), static_cast<DOMElement*>(childNode));
169 childObject.release();
171 else if (childNode->getNodeType() == DOMNode::TEXT_NODE) {
172 XT_log.debug("processing element content");
173 processElementContent(childNode->getNodeValue());
178 void AbstractXMLObjectUnmarshaller::processChildElement(XMLObject* child, const DOMElement* childRoot)
180 throw UnmarshallingException("Invalid child element: $1",params(1,child->getElementQName().toString().c_str()));