-/*\r
-* Copyright 2001-2006 Internet2\r
- * \r
-* Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-/**\r
- * AbstractXMLObjectUnmarshaller.cpp\r
- * \r
- * A thread-safe abstract unmarshaller.\r
- */\r
-\r
-#include "internal.h"\r
-#include "DOMCachingXMLObject.h"\r
-#include "exceptions.h"\r
-#include "XMLObjectBuilder.h"\r
-#include "io/AbstractXMLObjectUnmarshaller.h"\r
-#include "util/NDC.h"\r
-#include "util/XMLConstants.h"\r
-#include "util/XMLHelper.h"\r
-\r
-#include <xercesc/util/XMLUniDefs.hpp>\r
-#include <log4cpp/Category.hh>\r
-\r
-using namespace xmltooling;\r
-using namespace log4cpp;\r
-using namespace std;\r
-\r
-#define XT_log (*static_cast<Category*>(m_log))\r
-\r
-AbstractXMLObjectUnmarshaller::AbstractXMLObjectUnmarshaller(const XMLCh* targetNamespaceURI, const XMLCh* targetLocalName)\r
- : m_targetQName(targetNamespaceURI, targetLocalName),\r
- m_log(&Category::getInstance(XMLTOOLING_LOGCAT".Unmarshaller")) {\r
- if (!targetLocalName || !*targetLocalName)\r
- throw UnmarshallingException("targetLocalName cannot be null or empty");\r
-}\r
-\r
-XMLObject* AbstractXMLObjectUnmarshaller::unmarshall(DOMElement* element, bool bindDocument) const\r
-{\r
-#ifdef _DEBUG\r
- xmltooling::NDC ndc("unmarshall");\r
-#endif\r
-\r
- if (XT_log.isDebugEnabled()) {\r
- auto_ptr_char dname(element->getLocalName());\r
- XT_log.debug("unmarshalling DOM element %s", dname.get());\r
- }\r
-\r
- XMLObject* xmlObject = buildXMLObject(element);\r
-\r
- if (element->hasAttributes()) {\r
- unmarshallAttributes(element, xmlObject);\r
- }\r
-\r
- if (element->getTextContent()) {\r
- processElementContent(xmlObject, element->getTextContent());\r
- }\r
-\r
- unmarshallChildElements(element, xmlObject);\r
-\r
- /* TODO: Signing\r
- if (xmlObject instanceof SignableXMLObject) {\r
- verifySignature(domElement, xmlObject);\r
- }\r
- */\r
-\r
- DOMCachingXMLObject* dc=dynamic_cast<DOMCachingXMLObject*>(xmlObject);\r
- if (dc)\r
- dc->setDOM(element,bindDocument);\r
- \r
- return xmlObject;\r
-}\r
-\r
-XMLObject* AbstractXMLObjectUnmarshaller::buildXMLObject(const DOMElement* domElement) const\r
-{\r
- const XMLObjectBuilder* xmlObjectBuilder = XMLObjectBuilder::getBuilder(domElement);\r
- if (xmlObjectBuilder)\r
- return xmlObjectBuilder->buildObject();\r
- throw UnmarshallingException("Failed to locate XMLObjectBuilder for element.");\r
-}\r
-\r
-void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domElement, XMLObject* xmlObject) const\r
-{\r
-#ifdef _DEBUG\r
- xmltooling::NDC ndc("unmarshallAttributes");\r
-#endif\r
- static const XMLCh type[]={chLatin_t, chLatin_y, chLatin_p, chLatin_e, chNull};\r
-\r
- if (XT_log.isDebugEnabled()) {\r
- auto_ptr_char dname(domElement->getLocalName());\r
- XT_log.debug("unmarshalling attributes for DOM element %s", dname.get());\r
- }\r
-\r
- DOMNamedNodeMap* attributes = domElement->getAttributes();\r
- if (!attributes) {\r
- XT_log.debug("no attributes to unmarshall");\r
- return;\r
- }\r
-\r
- DOMNode* childNode;\r
- DOMAttr* attribute;\r
- for (XMLSize_t i=0; i<attributes->getLength(); i++) {\r
- childNode = attributes->item(i);\r
-\r
- // The child node should always be an attribute, but just in case\r
- if (childNode->getNodeType() != DOMNode::ATTRIBUTE_NODE) {\r
- XT_log.debug("encountered child node of type %d in attribute list, ignoring it", childNode->getNodeType());\r
- continue;\r
- }\r
-\r
- attribute = static_cast<DOMAttr*>(childNode);\r
- \r
- const XMLCh* nsuri=attribute->getNamespaceURI();\r
- if (!XMLString::compareString(nsuri,XMLConstants::XMLNS_NS)) {\r
- XT_log.debug("found namespace declaration, adding it to the list of namespaces on the XMLObject");\r
- xmlObject->addNamespace(Namespace(attribute->getValue(), attribute->getLocalName()));\r
- continue;\r
- }\r
- else if (!XMLString::compareString(nsuri,XMLConstants::XSI_NS) &&\r
- !XMLString::compareString(attribute->getLocalName(),type)) {\r
- XT_log.debug("found xsi:type declaration, setting the schema type of the XMLObject");\r
- auto_ptr<QName> xsitype(XMLHelper::getAttributeValueAsQName(attribute));\r
- xmlObject->setSchemaType(xsitype.get());\r
- continue;\r
- }\r
-\r
- XT_log.debug("processing generic attribute");\r
- processAttribute(xmlObject, attribute);\r
- }\r
-}\r
-\r
-void AbstractXMLObjectUnmarshaller::unmarshallChildElements(const DOMElement* domElement, XMLObject* xmlObject) const\r
-{\r
-#ifdef _DEBUG\r
- xmltooling::NDC ndc("unmarshallChildElements");\r
-#endif\r
-\r
- if (XT_log.isDebugEnabled()) {\r
- auto_ptr_char dname(domElement->getLocalName());\r
- XT_log.debug("unmarshalling child elements of DOM element %s", dname.get());\r
- }\r
-\r
- DOMNodeList* childNodes = domElement->getChildNodes();\r
- DOMNode* childNode;\r
- const Unmarshaller* unmarshaller;\r
- if (!childNodes || childNodes->getLength()==0) {\r
- XT_log.debug("element had no children");\r
- return;\r
- }\r
-\r
- XMLToolingConfig& config=XMLToolingConfig::getConfig();\r
- for (XMLSize_t i = 0; i < childNodes->getLength(); i++) {\r
- childNode = childNodes->item(i);\r
- if (childNode->getNodeType() == DOMNode::ELEMENT_NODE) {\r
- unmarshaller = Unmarshaller::getUnmarshaller(static_cast<DOMElement*>(childNode));\r
- if (!unmarshaller) {\r
- if (config.ignoreUnknownElements) {\r
- unmarshaller=Unmarshaller::getDefaultUnmarshaller();\r
- if (!unmarshaller) {\r
- auto_ptr<QName> cname(XMLHelper::getNodeQName(childNode));\r
- XT_log.error(\r
- "no default unmarshaller installed, found unknown child element %s",\r
- cname->toString().c_str()\r
- );\r
- throw UnmarshallingException(\r
- "Unmarshaller found unknown child element, but no default unmarshaller was found."\r
- );\r
- }\r
- else {\r
- XT_log.debug("using default unmarshaller");\r
- }\r
- }\r
- else {\r
- auto_ptr<QName> cname(XMLHelper::getNodeQName(childNode));\r
- XT_log.error("detected unknown child element %s", cname->toString().c_str());\r
- throw UnknownElementException("Unmarshaller found unknown child element.");\r
- }\r
- }\r
-\r
- if (XT_log.isDebugEnabled()) {\r
- auto_ptr<QName> cname(XMLHelper::getNodeQName(childNode));\r
- XT_log.debug("unmarshalling child element %s", cname->toString().c_str());\r
- }\r
- processChildElement(xmlObject, unmarshaller->unmarshall(static_cast<DOMElement*>(childNode)));\r
- }\r
- }\r
-}\r
+/**
+ * Licensed to the University Corporation for Advanced Internet
+ * Development, Inc. (UCAID) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * UCAID licenses this file to you 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 <xercesc/util/XMLUniDefs.hpp>
+
+using namespace xmlconstants;
+using namespace xmltooling;
+using namespace xercesc;
+using namespace std;
+
+AbstractXMLObjectUnmarshaller::AbstractXMLObjectUnmarshaller()
+{
+}
+
+AbstractXMLObjectUnmarshaller::~AbstractXMLObjectUnmarshaller()
+{
+}
+
+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 (m_log.isDebugEnabled()) {
+ auto_ptr_char dname(element->getNodeName());
+ m_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 (m_log.isDebugEnabled()) {
+ auto_ptr_char dname(domElement->getNodeName());
+ m_log.debug("unmarshalling attributes for DOM element (%s)", dname.get());
+ }
+
+ DOMNamedNodeMap* attributes = domElement->getAttributes();
+ if (!attributes) {
+ m_log.debug("no attributes to unmarshall");
+ return;
+ }
+
+ DOMNode* childNode;
+ DOMAttr* attribute;
+ for (XMLSize_t i=0; i<attributes->getLength(); i++) {
+ childNode = attributes->item(i);
+
+ // The child node should always be an attribute, but just in case
+ if (childNode->getNodeType() != DOMNode::ATTRIBUTE_NODE) {
+ m_log.debug("encountered child node of type %d in attribute list, ignoring it", childNode->getNodeType());
+ continue;
+ }
+
+ attribute = static_cast<DOMAttr*>(childNode);
+
+ const XMLCh* nsuri=attribute->getNamespaceURI();
+ if (XMLString::equals(nsuri,XMLNS_NS)) {
+ if (XMLString::equals(attribute->getLocalName(),XMLNS_PREFIX)) {
+ m_log.debug("found default namespace declaration, adding it to the list of namespaces on the XMLObject");
+ addNamespace(Namespace(attribute->getValue(), nullptr, true));
+ }
+ else if (XMLString::equals(attribute->getLocalName(),XML_PREFIX) && XMLString::equals(attribute->getNodeValue(),XML_NS)) {
+ m_log.debug("found standard xml prefix declaration, ignoring as superfluous");
+ }
+ else {
+ m_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,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);
+ static const XMLCh noNamespaceSchemaLocation[]= UNICODE_LITERAL_25(n,o,N,a,m,e,s,p,a,c,e,S,c,h,e,m,a,L,o,c,a,t,i,o,n);
+ static const XMLCh _nil[]= UNICODE_LITERAL_3(n,i,l);
+ if (XMLString::equals(attribute->getLocalName(),type)) {
+ m_log.debug("skipping xsi:type declaration");
+ continue;
+ }
+ else if (XMLString::equals(attribute->getLocalName(),schemaLocation)) {
+ m_log.debug("storing off xsi:schemaLocation attribute");
+ if (m_schemaLocation)
+ XMLString::release(&m_schemaLocation);
+ m_schemaLocation=XMLString::replicate(attribute->getValue());
+ continue;
+ }
+ else if (XMLString::equals(attribute->getLocalName(),noNamespaceSchemaLocation)) {
+ m_log.debug("storing off xsi:noNamespaceSchemaLocation attribute");
+ if (m_noNamespaceSchemaLocation)
+ XMLString::release(&m_noNamespaceSchemaLocation);
+ m_schemaLocation=XMLString::replicate(attribute->getValue());
+ m_noNamespaceSchemaLocation=XMLString::replicate(attribute->getValue());
+ continue;
+ }
+ else if (XMLString::equals(attribute->getLocalName(), _nil)) {
+ m_log.debug("processing xsi:nil attribute");
+ setNil(attribute->getValue());
+ continue;
+ }
+ // Note that the prefix is visibly used.
+ addNamespace(Namespace(nsuri, attribute->getPrefix(), false, Namespace::VisiblyUsed));
+ }
+ else if (nsuri && !XMLString::equals(nsuri,XML_NS)) {
+ m_log.debug("found namespace-qualified attribute, adding prefix to the list of visible namespaces on the XMLObject");
+ addNamespace(Namespace(nsuri, attribute->getPrefix(), false, Namespace::VisiblyUsed));
+ }
+
+ m_log.debug("processing generic attribute");
+ processAttribute(attribute);
+ }
+}
+
+void AbstractXMLObjectUnmarshaller::unmarshallContent(const DOMElement* domElement)
+{
+#ifdef _DEBUG
+ xmltooling::NDC ndc("unmarshallContent");
+#endif
+
+ if (m_log.isDebugEnabled()) {
+ auto_ptr_char dname(domElement->getNodeName());
+ m_log.debug("unmarshalling child nodes of DOM element (%s)", dname.get());
+ }
+
+ DOMNode* childNode = domElement->getFirstChild();
+ if (!childNode) {
+ m_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<DOMElement*>(childNode));
+ if (!builder) {
+ auto_ptr<QName> cname(XMLHelper::getNodeQName(childNode));
+ m_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 (m_log.isDebugEnabled()) {
+ auto_ptr<QName> cname(XMLHelper::getNodeQName(childNode));
+ m_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<XMLObject> childObject(builder->buildFromElement(static_cast<DOMElement*>(childNode)));
+ processChildElement(childObject.get(), static_cast<DOMElement*>(childNode));
+ childObject.release();
+
+ // Advance the text node position marker.
+ ++position;
+ }
+ else if (childNode->getNodeType() == DOMNode::TEXT_NODE || childNode->getNodeType() == DOMNode::CDATA_SECTION_NODE) {
+ m_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<QName> q(XMLHelper::getNodeQName(attribute));
+ throw UnmarshallingException("Invalid attribute: $1",params(1,q->toString().c_str()));
+}