X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=xmltooling%2Fio%2FAbstractXMLObjectUnmarshaller.cpp;h=0ba988a3873b52faf70f2eac3b6cf1db7e2028de;hb=77769b2e300d1295b8a5d717d9ede50e27d70cea;hp=ce3f358f9350834f6815a4d6250f80abe9fca5b7;hpb=8bbee91cee3a23e008eeab7cb238f16cbd5ac806;p=shibboleth%2Fcpp-xmltooling.git diff --git a/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp b/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp index ce3f358..0ba988a 100644 --- a/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp +++ b/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp @@ -1,197 +1,195 @@ -/* -* Copyright 2001-2006 Internet2 - * -* Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * AbstractXMLObjectUnmarshaller.cpp - * - * A thread-safe abstract unmarshaller. - */ - -#include "internal.h" -#include "DOMCachingXMLObject.h" -#include "exceptions.h" -#include "XMLObjectBuilder.h" -#include "io/AbstractXMLObjectUnmarshaller.h" -#include "util/NDC.h" -#include "util/XMLConstants.h" -#include "util/XMLHelper.h" - -#include -#include - -using namespace xmltooling; -using namespace log4cpp; -using namespace std; - -#define XT_log (*static_cast(m_log)) - -AbstractXMLObjectUnmarshaller::AbstractXMLObjectUnmarshaller(const XMLCh* targetNamespaceURI, const XMLCh* targetLocalName) - : m_targetQName(targetNamespaceURI, targetLocalName), - m_log(&Category::getInstance(XMLTOOLING_LOGCAT".Unmarshaller")) { - if (!targetLocalName || !*targetLocalName) - throw UnmarshallingException("targetLocalName cannot be null or empty"); -} - -XMLObject* AbstractXMLObjectUnmarshaller::unmarshall(DOMElement* element, bool bindDocument) const -{ -#ifdef _DEBUG - xmltooling::NDC ndc("unmarshall"); -#endif - - if (XT_log.isDebugEnabled()) { - auto_ptr_char dname(element->getLocalName()); - XT_log.debug("unmarshalling DOM element %s", dname.get()); - } - - XMLObject* xmlObject = buildXMLObject(element); - - if (element->hasAttributes()) { - unmarshallAttributes(element, xmlObject); - } - - if (element->getTextContent()) { - processElementContent(xmlObject, element->getTextContent()); - } - - unmarshallChildElements(element, xmlObject); - - /* TODO: Signing - if (xmlObject instanceof SignableXMLObject) { - verifySignature(domElement, xmlObject); - } - */ - - DOMCachingXMLObject* dc=dynamic_cast(xmlObject); - if (dc) - dc->setDOM(element,bindDocument); - - return xmlObject; -} - -XMLObject* AbstractXMLObjectUnmarshaller::buildXMLObject(const DOMElement* domElement) const -{ - const XMLObjectBuilder* xmlObjectBuilder = XMLObjectBuilder::getBuilder(domElement); - if (xmlObjectBuilder) - return xmlObjectBuilder->buildObject(); - throw UnmarshallingException("Failed to locate XMLObjectBuilder for element."); -} - -void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domElement, XMLObject* xmlObject) const -{ -#ifdef _DEBUG - xmltooling::NDC ndc("unmarshallAttributes"); -#endif - static const XMLCh type[]={chLatin_t, chLatin_y, chLatin_p, chLatin_e, chNull}; - - if (XT_log.isDebugEnabled()) { - auto_ptr_char dname(domElement->getLocalName()); - XT_log.debug("unmarshalling attributes for DOM element %s", dname.get()); - } - - DOMNamedNodeMap* attributes = domElement->getAttributes(); - if (!attributes) { - XT_log.debug("no attributes to unmarshall"); - return; - } - - DOMNode* childNode; - DOMAttr* attribute; - for (XMLSize_t i=0; igetLength(); i++) { - childNode = attributes->item(i); - - // The child node should always be an attribute, but just in case - if (childNode->getNodeType() != DOMNode::ATTRIBUTE_NODE) { - XT_log.debug("encountered child node of type %d in attribute list, ignoring it", childNode->getNodeType()); - continue; - } - - attribute = static_cast(childNode); - - const XMLCh* nsuri=attribute->getNamespaceURI(); - if (!XMLString::compareString(nsuri,XMLConstants::XMLNS_NS)) { - XT_log.debug("found namespace declaration, adding it to the list of namespaces on the XMLObject"); - xmlObject->addNamespace(Namespace(attribute->getValue(), attribute->getLocalName())); - continue; - } - else if (!XMLString::compareString(nsuri,XMLConstants::XSI_NS) && - !XMLString::compareString(attribute->getLocalName(),type)) { - XT_log.debug("found xsi:type declaration, setting the schema type of the XMLObject"); - auto_ptr xsitype(XMLHelper::getAttributeValueAsQName(attribute)); - xmlObject->setSchemaType(xsitype.get()); - continue; - } - - XT_log.debug("processing generic attribute"); - processAttribute(xmlObject, attribute); - } -} - -void AbstractXMLObjectUnmarshaller::unmarshallChildElements(const DOMElement* domElement, XMLObject* xmlObject) const -{ -#ifdef _DEBUG - xmltooling::NDC ndc("unmarshallChildElements"); -#endif - - if (XT_log.isDebugEnabled()) { - auto_ptr_char dname(domElement->getLocalName()); - XT_log.debug("unmarshalling child elements of DOM element %s", dname.get()); - } - - DOMNodeList* childNodes = domElement->getChildNodes(); - DOMNode* childNode; - const Unmarshaller* unmarshaller; - if (!childNodes || childNodes->getLength()==0) { - XT_log.debug("element had no children"); - return; - } - - XMLToolingConfig& config=XMLToolingConfig::getConfig(); - for (XMLSize_t i = 0; i < childNodes->getLength(); i++) { - childNode = childNodes->item(i); - if (childNode->getNodeType() == DOMNode::ELEMENT_NODE) { - unmarshaller = Unmarshaller::getUnmarshaller(static_cast(childNode)); - if (!unmarshaller) { - if (config.ignoreUnknownElements) { - unmarshaller=Unmarshaller::getDefaultUnmarshaller(); - if (!unmarshaller) { - auto_ptr cname(XMLHelper::getNodeQName(childNode)); - XT_log.error( - "no default unmarshaller installed, found unknown child element %s", - cname->toString().c_str() - ); - throw UnmarshallingException( - "Unmarshaller found unknown child element, but no default unmarshaller was found." - ); - } - else { - XT_log.debug("using default unmarshaller"); - } - } - else { - auto_ptr cname(XMLHelper::getNodeQName(childNode)); - XT_log.error("detected unknown child element %s", cname->toString().c_str()); - throw UnknownElementException("Unmarshaller found unknown child element."); - } - } - - if (XT_log.isDebugEnabled()) { - auto_ptr cname(XMLHelper::getNodeQName(childNode)); - XT_log.debug("unmarshalling child element %s", cname->toString().c_str()); - } - processChildElement(xmlObject, unmarshaller->unmarshall(static_cast(childNode))); - } - } -} +/* +* Copyright 2001-2006 Internet2 + * +* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * AbstractXMLObjectUnmarshaller.cpp + * + * A thread-safe abstract unmarshaller. + */ + +#include "internal.h" +#include "exceptions.h" +#include "XMLObjectBuilder.h" +#include "io/AbstractXMLObjectUnmarshaller.h" +#include "util/NDC.h" +#include "util/XMLConstants.h" +#include "util/XMLHelper.h" + +#include +#include + +using namespace xmltooling; +using namespace log4cpp; +using namespace std; + +#define XT_log (*static_cast(m_log)) + +XMLObject* AbstractXMLObjectUnmarshaller::unmarshall(DOMElement* element, bool bindDocument) +{ +#ifdef _DEBUG + xmltooling::NDC ndc("unmarshall"); +#endif + + if (getDOM() || hasParent()) + throw UnmarshallingException("Object already contains data, it cannot be unmarshalled at this stage."); + + if (!XMLString::equals(element->getNamespaceURI(),getElementQName().getNamespaceURI()) || + !XMLString::equals(element->getLocalName(),getElementQName().getLocalPart())) { + throw UnmarshallingException("Unrecognized element supplied to implementation for unmarshalling."); + } + + if (XT_log.isDebugEnabled()) { + auto_ptr_char dname(element->getNodeName()); + XT_log.debug("unmarshalling DOM element (%s)", dname.get()); + } + + if (element->hasAttributes()) { + unmarshallAttributes(element); + } + + unmarshallContent(element); + + setDOM(element,bindDocument); + return this; +} + +void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domElement) +{ +#ifdef _DEBUG + xmltooling::NDC ndc("unmarshallAttributes"); +#endif + + if (XT_log.isDebugEnabled()) { + auto_ptr_char dname(domElement->getNodeName()); + XT_log.debug("unmarshalling attributes for DOM element (%s)", dname.get()); + } + + DOMNamedNodeMap* attributes = domElement->getAttributes(); + if (!attributes) { + XT_log.debug("no attributes to unmarshall"); + return; + } + + DOMNode* childNode; + DOMAttr* attribute; + for (XMLSize_t i=0; igetLength(); i++) { + childNode = attributes->item(i); + + // The child node should always be an attribute, but just in case + if (childNode->getNodeType() != DOMNode::ATTRIBUTE_NODE) { + XT_log.debug("encountered child node of type %d in attribute list, ignoring it", childNode->getNodeType()); + continue; + } + + attribute = static_cast(childNode); + + const XMLCh* nsuri=attribute->getNamespaceURI(); + if (XMLString::equals(nsuri,XMLConstants::XMLNS_NS)) { + if (XMLString::equals(attribute->getLocalName(),XMLConstants::XMLNS_PREFIX)) { + XT_log.debug("found default namespace declaration, adding it to the list of namespaces on the XMLObject"); + addNamespace(Namespace(attribute->getValue(), NULL, true)); + continue; + } + else { + XT_log.debug("found namespace declaration, adding it to the list of namespaces on the XMLObject"); + addNamespace(Namespace(attribute->getValue(), attribute->getLocalName(), true)); + continue; + } + } + else if (XMLString::equals(nsuri,XMLConstants::XSI_NS)) { + static const XMLCh type[]= UNICODE_LITERAL_4(t,y,p,e); + static const XMLCh schemaLocation[]= UNICODE_LITERAL_14(s,c,h,e,m,a,L,o,c,a,t,i,o,n); + if (XMLString::equals(attribute->getLocalName(),type)) { + XT_log.debug("skipping xsi:type declaration"); + continue; + } + else if (XMLString::equals(attribute->getLocalName(),schemaLocation)) { + XT_log.debug("storing off xsi:schemaLocation attribute"); + if (m_schemaLocation) + XMLString::release(&m_schemaLocation); + m_schemaLocation=XMLString::replicate(attribute->getValue()); + continue; + } + } + else if (nsuri && !XMLString::equals(nsuri,XMLConstants::XML_NS)) { + XT_log.debug("found namespace-qualified attribute, adding prefix to the list of namespaces on the XMLObject"); + addNamespace(Namespace(nsuri, attribute->getPrefix())); + } + + XT_log.debug("processing generic attribute"); + processAttribute(attribute); + } +} + +void AbstractXMLObjectUnmarshaller::unmarshallContent(const DOMElement* domElement) +{ +#ifdef _DEBUG + xmltooling::NDC ndc("unmarshallContent"); +#endif + + if (XT_log.isDebugEnabled()) { + auto_ptr_char dname(domElement->getNodeName()); + XT_log.debug("unmarshalling child nodes of DOM element (%s)", dname.get()); + } + + DOMNode* childNode = domElement->getFirstChild(); + if (!childNode) { + XT_log.debug("element had no children"); + return; + } + + unsigned int position = 0; + while (childNode) { + if (childNode->getNodeType() == DOMNode::ELEMENT_NODE) { + const XMLObjectBuilder* builder = XMLObjectBuilder::getBuilder(static_cast(childNode)); + if (!builder) { + auto_ptr cname(XMLHelper::getNodeQName(childNode)); + XT_log.error("no default builder installed, found unknown child element (%s)", cname->toString().c_str()); + throw UnmarshallingException("Unmarshaller found unknown child element, but no default builder was found."); + } + + if (XT_log.isDebugEnabled()) { + auto_ptr cname(XMLHelper::getNodeQName(childNode)); + XT_log.debug("unmarshalling child element (%s)", cname->toString().c_str()); + } + + // Retain ownership of the unmarshalled child until it's processed by the parent. + auto_ptr childObject(builder->buildFromElement(static_cast(childNode))); + processChildElement(childObject.get(), static_cast(childNode)); + childObject.release(); + + // Advance the text node position marker. + ++position; + } + else if (childNode->getNodeType() == DOMNode::TEXT_NODE) { + XT_log.debug("processing text content at position (%d)", position); + setTextContent(childNode->getNodeValue(), position); + } + + childNode = childNode->getNextSibling(); + } +} + +void AbstractXMLObjectUnmarshaller::processChildElement(XMLObject* child, const DOMElement* childRoot) +{ + throw UnmarshallingException("Invalid child element: $1",params(1,child->getElementQName().toString().c_str())); +} + +void AbstractXMLObjectUnmarshaller::processAttribute(const DOMAttr* attribute) +{ + auto_ptr q(XMLHelper::getNodeQName(attribute)); + throw UnmarshallingException("Invalid attribute: $1",params(1,q->toString().c_str())); +}