Handle variant element names, merge in wildcard class, add test cases.
[shibboleth/cpp-xmltooling.git] / xmltooling / impl / AnyElement.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  * @file AnyElement.h
19  * 
20  * Advanced anyType implementation suitable for deep processing of unknown content.
21  */
22
23 #include "internal.h"
24 #include "AbstractAttributeExtensibleXMLObject.h"
25 #include "AbstractElementProxy.h"
26 #include "exceptions.h"
27 #include "impl/AnyElement.h"
28 #include "io/AbstractXMLObjectMarshaller.h"
29 #include "io/AbstractXMLObjectUnmarshaller.h"
30 #include "util/NDC.h"
31 #include "util/XMLHelper.h"
32
33 #include <log4cpp/Category.hh>
34 #include <xercesc/util/XMLUniDefs.hpp>
35
36 using namespace xmltooling;
37 using namespace log4cpp;
38 using namespace std;
39
40 #if defined (_MSC_VER)
41     #pragma warning( push )
42     #pragma warning( disable : 4250 4251 )
43 #endif
44
45 namespace xmltooling {
46
47     /**
48      * Implements a smart wrapper around unknown DOM content.
49      */
50     class XMLTOOL_DLLLOCAL AnyElementImpl : public AbstractElementProxy, public AbstractAttributeExtensibleXMLObject,
51         public AbstractXMLObjectMarshaller, public AbstractXMLObjectUnmarshaller
52     {
53     public:
54         AnyElementImpl(const XMLCh* nsURI, const XMLCh* localName, const XMLCh* prefix)
55             : AbstractDOMCachingXMLObject(nsURI, localName, prefix),
56             AbstractElementProxy(nsURI, localName, prefix),
57             AbstractAttributeExtensibleXMLObject(nsURI, localName, prefix) {}
58         virtual ~AnyElementImpl() {}
59         
60         AnyElementImpl* clone() const {
61             auto_ptr<XMLObject> domClone(AbstractDOMCachingXMLObject::clone());
62             AnyElementImpl* ret=dynamic_cast<AnyElementImpl*>(domClone.get());
63             if (ret) {
64                 domClone.release();
65                 return ret;
66             }
67
68             ret=new AnyElementImpl(
69                 getElementQName().getNamespaceURI(),getElementQName().getLocalPart(),getElementQName().getPrefix()
70                 );
71             ret->m_namespaces=m_namespaces;
72             for (map<QName,XMLCh*>::const_iterator i=m_attributeMap.begin(); i!=m_attributeMap.end(); i++) {
73                 ret->m_attributeMap[i->first]=XMLString::replicate(i->second);
74             }
75             ret->setTextContent(getTextContent());
76             xmltooling::clone(m_children, ret->m_children);
77             return ret;
78         }
79
80         void marshallAttributes(DOMElement* domElement) const {
81             for (map<QName,XMLCh*>::const_iterator i=m_attributeMap.begin(); i!=m_attributeMap.end(); i++) {
82                 DOMAttr* attr=domElement->getOwnerDocument()->createAttributeNS(i->first.getNamespaceURI(),i->first.getLocalPart());
83                 if (i->first.hasPrefix())
84                     attr->setPrefix(i->first.getPrefix());
85                 attr->setNodeValue(i->second);
86                 domElement->setAttributeNode(attr);
87             }
88         }
89
90         void marshallElementContent(DOMElement* domElement) const {
91             if(getTextContent()) {
92                 domElement->appendChild(domElement->getOwnerDocument()->createTextNode(getTextContent()));
93             }
94         }
95
96         void processChildElement(XMLObject* childXMLObject, const DOMElement* root) {
97             getXMLObjects().push_back(childXMLObject);
98         }
99
100         void processAttribute(const DOMAttr* attribute) {
101             QName q(attribute->getNamespaceURI(),attribute->getLocalName(),attribute->getPrefix()); 
102             setAttribute(q,attribute->getNodeValue());
103         }
104
105         void processElementContent(const XMLCh* elementContent) {
106             setTextContent(elementContent);
107         }
108     };
109
110 };
111
112 #if defined (_MSC_VER)
113     #pragma warning( pop )
114 #endif
115
116
117 XMLObject* AnyElementBuilder::buildObject(
118     const XMLCh* namespaceURI, const XMLCh* elementLocalName, const XMLCh* namespacePrefix
119     ) const {
120     if (XMLString::stringLen(elementLocalName)==0)
121         throw XMLObjectException("Constructing this object requires an element name.");
122     return new AnyElementImpl(namespaceURI,elementLocalName,namespacePrefix);
123 }