Removed unnecessary class from string literals.
[shibboleth/cpp-xmltooling.git] / xmltooling / io / AbstractXMLObjectUnmarshaller.cpp
1 /*
2 *  Copyright 2001-2006 Internet2
3  * 
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 /**
18  * AbstractXMLObjectUnmarshaller.cpp
19  * 
20  * A thread-safe abstract unmarshaller.
21  */
22
23 #include "internal.h"
24 #include "exceptions.h"
25 #include "XMLObjectBuilder.h"
26 #include "io/AbstractXMLObjectUnmarshaller.h"
27 #include "util/NDC.h"
28 #include "util/XMLConstants.h"
29 #include "util/XMLHelper.h"
30
31 #include <xercesc/util/XMLUniDefs.hpp>
32 #include <log4cpp/Category.hh>
33
34 using namespace xmlconstants;
35 using namespace xmltooling;
36 using namespace log4cpp;
37 using namespace std;
38
39 #define XT_log (*static_cast<Category*>(m_log))
40
41 XMLObject* AbstractXMLObjectUnmarshaller::unmarshall(DOMElement* element, bool bindDocument)
42 {
43 #ifdef _DEBUG
44     xmltooling::NDC ndc("unmarshall");
45 #endif
46
47     if (getDOM() || hasParent())
48         throw UnmarshallingException("Object already contains data, it cannot be unmarshalled at this stage.");
49
50     if (!XMLString::equals(element->getNamespaceURI(),getElementQName().getNamespaceURI()) ||
51         !XMLString::equals(element->getLocalName(),getElementQName().getLocalPart())) {
52         throw UnmarshallingException("Unrecognized element supplied to implementation for unmarshalling.");
53     }
54
55     if (XT_log.isDebugEnabled()) {
56         auto_ptr_char dname(element->getNodeName());
57         XT_log.debug("unmarshalling DOM element (%s)", dname.get());
58     }
59
60     if (element->hasAttributes()) {
61         unmarshallAttributes(element);
62     }
63
64     unmarshallContent(element);
65
66     setDOM(element,bindDocument);
67     return this;
68 }
69
70 void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domElement)
71 {
72 #ifdef _DEBUG
73     xmltooling::NDC ndc("unmarshallAttributes");
74 #endif
75
76     if (XT_log.isDebugEnabled()) {
77         auto_ptr_char dname(domElement->getNodeName());
78         XT_log.debug("unmarshalling attributes for DOM element (%s)", dname.get());
79     }
80
81     DOMNamedNodeMap* attributes = domElement->getAttributes();
82     if (!attributes) {
83         XT_log.debug("no attributes to unmarshall");
84         return;
85     }
86
87     DOMNode* childNode;
88     DOMAttr* attribute;
89     for (XMLSize_t i=0; i<attributes->getLength(); i++) {
90         childNode = attributes->item(i);
91
92         // The child node should always be an attribute, but just in case
93         if (childNode->getNodeType() != DOMNode::ATTRIBUTE_NODE) {
94             XT_log.debug("encountered child node of type %d in attribute list, ignoring it", childNode->getNodeType());
95             continue;
96         }
97
98         attribute = static_cast<DOMAttr*>(childNode);
99         
100         const XMLCh* nsuri=attribute->getNamespaceURI();
101         if (XMLString::equals(nsuri,XMLNS_NS)) {
102             if (XMLString::equals(attribute->getLocalName(),XMLNS_PREFIX)) {
103                 XT_log.debug("found default namespace declaration, adding it to the list of namespaces on the XMLObject");
104                 addNamespace(Namespace(attribute->getValue(), NULL, true));
105                 continue;
106             }
107             else {
108                 XT_log.debug("found namespace declaration, adding it to the list of namespaces on the XMLObject");
109                 addNamespace(Namespace(attribute->getValue(), attribute->getLocalName(), true));
110                 continue;
111             }
112         }
113         else if (XMLString::equals(nsuri,XSI_NS)) {
114             static const XMLCh type[]= UNICODE_LITERAL_4(t,y,p,e);
115             static const XMLCh schemaLocation[]= UNICODE_LITERAL_14(s,c,h,e,m,a,L,o,c,a,t,i,o,n);
116             if (XMLString::equals(attribute->getLocalName(),type)) {
117                 XT_log.debug("skipping xsi:type declaration");
118                 continue;
119             }
120             else if (XMLString::equals(attribute->getLocalName(),schemaLocation)) {
121                 XT_log.debug("storing off xsi:schemaLocation attribute");
122                 if (m_schemaLocation)
123                     XMLString::release(&m_schemaLocation);
124                 m_schemaLocation=XMLString::replicate(attribute->getValue());
125                 continue;
126             }
127         }
128         else if (nsuri && !XMLString::equals(nsuri,XML_NS)) {
129             XT_log.debug("found namespace-qualified attribute, adding prefix to the list of namespaces on the XMLObject");
130             addNamespace(Namespace(nsuri, attribute->getPrefix()));
131         }
132
133         XT_log.debug("processing generic attribute");
134         processAttribute(attribute);
135     }
136 }
137
138 void AbstractXMLObjectUnmarshaller::unmarshallContent(const DOMElement* domElement)
139 {
140 #ifdef _DEBUG
141     xmltooling::NDC ndc("unmarshallContent");
142 #endif
143
144     if (XT_log.isDebugEnabled()) {
145         auto_ptr_char dname(domElement->getNodeName());
146         XT_log.debug("unmarshalling child nodes of DOM element (%s)", dname.get());
147     }
148
149     DOMNode* childNode = domElement->getFirstChild();
150     if (!childNode) {
151         XT_log.debug("element had no children");
152         return;
153     }
154
155     unsigned int position = 0;
156     while (childNode) {
157         if (childNode->getNodeType() == DOMNode::ELEMENT_NODE) {
158             const XMLObjectBuilder* builder = XMLObjectBuilder::getBuilder(static_cast<DOMElement*>(childNode));
159             if (!builder) {
160                 auto_ptr<QName> cname(XMLHelper::getNodeQName(childNode));
161                 XT_log.error("no default builder installed, found unknown child element (%s)", cname->toString().c_str());
162                 throw UnmarshallingException("Unmarshaller found unknown child element, but no default builder was found.");
163             }
164
165             if (XT_log.isDebugEnabled()) {
166                 auto_ptr<QName> cname(XMLHelper::getNodeQName(childNode));
167                 XT_log.debug("unmarshalling child element (%s)", cname->toString().c_str());
168             }
169
170             // Retain ownership of the unmarshalled child until it's processed by the parent.
171             auto_ptr<XMLObject> childObject(builder->buildFromElement(static_cast<DOMElement*>(childNode)));
172             processChildElement(childObject.get(), static_cast<DOMElement*>(childNode));
173             childObject.release();
174             
175             // Advance the text node position marker.
176             ++position;
177         }
178         else if (childNode->getNodeType() == DOMNode::TEXT_NODE) {
179             XT_log.debug("processing text content at position (%d)", position);
180             setTextContent(childNode->getNodeValue(), position);
181         }
182         
183         childNode = childNode->getNextSibling();
184     }
185 }
186
187 void AbstractXMLObjectUnmarshaller::processChildElement(XMLObject* child, const DOMElement* childRoot)
188 {
189     throw UnmarshallingException("Invalid child element: $1",params(1,child->getElementQName().toString().c_str()));
190 }
191
192 void AbstractXMLObjectUnmarshaller::processAttribute(const DOMAttr* attribute)
193 {
194     auto_ptr<QName> q(XMLHelper::getNodeQName(attribute));
195     throw UnmarshallingException("Invalid attribute: $1",params(1,q->toString().c_str()));
196 }