2 * Copyright 2001-2006 Internet2
\r
4 * Licensed under the Apache License, Version 2.0 (the "License");
\r
5 * you may not use this file except in compliance with the License.
\r
6 * You may obtain a copy of the License at
\r
8 * http://www.apache.org/licenses/LICENSE-2.0
\r
10 * Unless required by applicable law or agreed to in writing, software
\r
11 * distributed under the License is distributed on an "AS IS" BASIS,
\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 * See the License for the specific language governing permissions and
\r
14 * limitations under the License.
\r
18 * AbstractXMLObjectUnmarshaller.cpp
\r
20 * A thread-safe abstract unmarshaller.
\r
23 #include "internal.h"
\r
24 #include "DOMCachingXMLObject.h"
\r
25 #include "exceptions.h"
\r
26 #include "XMLObjectBuilder.h"
\r
27 #include "io/AbstractXMLObjectUnmarshaller.h"
\r
28 #include "util/NDC.h"
\r
29 #include "util/XMLConstants.h"
\r
30 #include "util/XMLHelper.h"
\r
32 #include <xercesc/util/XMLUniDefs.hpp>
\r
33 #include <log4cpp/Category.hh>
\r
35 using namespace xmltooling;
\r
36 using namespace log4cpp;
\r
37 using namespace std;
\r
39 #define XT_log (*static_cast<Category*>(m_log))
\r
41 AbstractXMLObjectUnmarshaller::AbstractXMLObjectUnmarshaller(const XMLCh* targetNamespaceURI, const XMLCh* targetLocalName)
\r
42 : m_targetQName(targetNamespaceURI, targetLocalName),
\r
43 m_log(&Category::getInstance(XMLTOOLING_LOGCAT".Unmarshaller")) {
\r
44 if (!targetLocalName || !*targetLocalName)
\r
45 throw UnmarshallingException("targetLocalName cannot be null or empty");
\r
48 XMLObject* AbstractXMLObjectUnmarshaller::unmarshall(DOMElement* element, bool bindDocument) const
\r
51 xmltooling::NDC ndc("unmarshall");
\r
54 if (XT_log.isDebugEnabled()) {
\r
55 auto_ptr_char dname(element->getLocalName());
\r
56 XT_log.debug("unmarshalling DOM element %s", dname.get());
\r
60 checkElementIsTarget(element);
\r
63 XMLObject* xmlObject = buildXMLObject(element);
\r
65 if (element->hasAttributes()) {
\r
66 unmarshallAttributes(element, xmlObject);
\r
69 if (element->getTextContent()) {
\r
70 processElementContent(xmlObject, element->getTextContent());
\r
73 unmarshallChildElements(element, xmlObject);
\r
76 if (xmlObject instanceof SignableXMLObject) {
\r
77 verifySignature(domElement, xmlObject);
\r
81 DOMCachingXMLObject* dc=dynamic_cast<DOMCachingXMLObject*>(xmlObject);
\r
83 dc->setDOM(element,bindDocument);
\r
88 void AbstractXMLObjectUnmarshaller::checkElementIsTarget(const DOMElement* domElement) const
\r
90 auto_ptr<QName> elementName(XMLHelper::getNodeQName(domElement));
\r
92 XT_log.debug("checking that root element meets target criteria");
\r
94 auto_ptr<QName> type(XMLHelper::getXSIType(domElement));
\r
96 if (type.get() && m_targetQName==*(type.get())) {
\r
97 XT_log.debug("schema type of element matches target");
\r
101 if (m_targetQName==*(elementName.get())) {
\r
102 XT_log.debug("element name matches target");
\r
106 XT_log.errorStream() << "unmarshaller for (" << m_targetQName.toString()
\r
107 << ") passed (" << elementName->toString() << ")" << CategoryStream::ENDLINE;
\r
108 throw UnmarshallingException("Incorrect element type passed to unmarshaller.");
\r
113 XMLObject* AbstractXMLObjectUnmarshaller::buildXMLObject(const DOMElement* domElement) const
\r
115 const XMLObjectBuilder* xmlObjectBuilder = XMLObjectBuilder::getBuilder(domElement);
\r
116 if (xmlObjectBuilder)
\r
117 return xmlObjectBuilder->buildObject();
\r
118 throw UnmarshallingException("Failed to locate XMLObjectBuilder for element.");
\r
121 void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domElement, XMLObject* xmlObject) const
\r
124 xmltooling::NDC ndc("unmarshallAttributes");
\r
126 static const XMLCh type[]={chLatin_t, chLatin_y, chLatin_p, chLatin_e, chNull};
\r
128 if (XT_log.isDebugEnabled()) {
\r
129 auto_ptr_char dname(domElement->getLocalName());
\r
130 XT_log.debug("unmarshalling attributes for DOM element %s", dname.get());
\r
133 DOMNamedNodeMap* attributes = domElement->getAttributes();
\r
135 XT_log.debug("no attributes to unmarshall");
\r
139 DOMNode* childNode;
\r
140 DOMAttr* attribute;
\r
141 for (XMLSize_t i=0; i<attributes->getLength(); i++) {
\r
142 childNode = attributes->item(i);
\r
144 // The child node should always be an attribute, but just in case
\r
145 if (childNode->getNodeType() != DOMNode::ATTRIBUTE_NODE) {
\r
146 XT_log.debug("encountered child node of type %d in attribute list, ignoring it", childNode->getNodeType());
\r
150 attribute = static_cast<DOMAttr*>(childNode);
\r
152 const XMLCh* nsuri=attribute->getNamespaceURI();
\r
153 if (!XMLString::compareString(nsuri,XMLConstants::XMLNS_NS)) {
\r
154 XT_log.debug("found namespace declaration, adding it to the list of namespaces on the XMLObject");
\r
155 xmlObject->addNamespace(Namespace(attribute->getValue(), attribute->getLocalName()));
\r
158 else if (!XMLString::compareString(nsuri,XMLConstants::XSI_NS) &&
\r
159 !XMLString::compareString(attribute->getLocalName(),type)) {
\r
160 XT_log.debug("found xsi:type declaration, setting the schema type of the XMLObject");
\r
161 auto_ptr<QName> xsitype(XMLHelper::getAttributeValueAsQName(attribute));
\r
162 xmlObject->setSchemaType(xsitype.get());
\r
166 XT_log.debug("processing generic attribute");
\r
167 processAttribute(xmlObject, attribute);
\r
171 void AbstractXMLObjectUnmarshaller::unmarshallChildElements(const DOMElement* domElement, XMLObject* xmlObject) const
\r
174 xmltooling::NDC ndc("unmarshallChildElements");
\r
177 if (XT_log.isDebugEnabled()) {
\r
178 auto_ptr_char dname(domElement->getLocalName());
\r
179 XT_log.debug("unmarshalling child elements of DOM element %s", dname.get());
\r
182 DOMNodeList* childNodes = domElement->getChildNodes();
\r
183 DOMNode* childNode;
\r
184 const Unmarshaller* unmarshaller;
\r
185 if (!childNodes || childNodes->getLength()==0) {
\r
186 XT_log.debug("element had no children");
\r
190 XMLToolingConfig& config=XMLToolingConfig::getConfig();
\r
191 for (XMLSize_t i = 0; i < childNodes->getLength(); i++) {
\r
192 childNode = childNodes->item(i);
\r
193 if (childNode->getNodeType() == DOMNode::ELEMENT_NODE) {
\r
194 unmarshaller = Unmarshaller::getUnmarshaller(static_cast<DOMElement*>(childNode));
\r
195 if (!unmarshaller) {
\r
196 if (config.ignoreUnknownElements) {
\r
197 unmarshaller=Unmarshaller::getDefaultUnmarshaller();
\r
198 if (!unmarshaller) {
\r
199 auto_ptr<QName> cname(XMLHelper::getNodeQName(childNode));
\r
200 XT_log.error("no default unmarshaller installed, detected unknown child element %s", cname->toString().c_str());
\r
201 throw UnmarshallingException("Unmarshaller detected unknown child element, but no default unmarshaller was found.");
\r
204 XT_log.debug("using default unmarshaller");
\r
208 auto_ptr<QName> cname(XMLHelper::getNodeQName(childNode));
\r
209 XT_log.error("detected unknown child element %s", cname->toString().c_str());
\r
210 throw UnknownElementException("Unmarshaller detected unknown child element.");
\r
214 if (XT_log.isDebugEnabled()) {
\r
215 auto_ptr<QName> cname(XMLHelper::getNodeQName(childNode));
\r
216 XT_log.debug("unmarshalling child element %s", cname->toString().c_str());
\r
218 processChildElement(xmlObject, unmarshaller->unmarshall(static_cast<DOMElement*>(childNode)));
\r