Merge branch '1.x' of ssh://authdev.it.ohio-state.edu/~scantor/git/cpp-xmltooling...
[shibboleth/cpp-xmltooling.git] / xmltooling / AbstractAttributeExtensibleXMLObject.cpp
1 /**
2  * Licensed to the University Corporation for Advanced Internet
3  * Development, Inc. (UCAID) under one or more contributor license
4  * agreements. See the NOTICE file distributed with this work for
5  * additional information regarding copyright ownership.
6  *
7  * UCAID licenses this file to you under the Apache License,
8  * Version 2.0 (the "License"); you may not use this file except
9  * in compliance with the License. You may obtain a copy of the
10  * License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17  * either express or implied. See the License for the specific
18  * language governing permissions and limitations under the License.
19  */
20
21 /**
22  * AbstractAttributeExtensibleXMLObject.cpp
23  * 
24  * Extension of AbstractDOMCachingXMLObject that implements an AttributeExtensibleXMLObject. 
25  */
26
27 #include "internal.h"
28 #include "AbstractAttributeExtensibleXMLObject.h"
29 #include "ElementExtensibleXMLObject.h"
30 #include "ElementProxy.h"
31
32 #include <algorithm>
33 #include <functional>
34 #include <xercesc/util/XMLUniDefs.hpp>
35
36 using namespace xmltooling;
37 using namespace std;
38 using xercesc::chColon;
39
40 using xercesc::DOMAttr;
41 using xercesc::DOMElement;
42 using xercesc::XMLString;
43
44 ElementExtensibleXMLObject::ElementExtensibleXMLObject()
45 {
46 }
47
48 ElementExtensibleXMLObject::~ElementExtensibleXMLObject()
49 {
50 }
51
52 ElementProxy::ElementProxy()
53 {
54 }
55
56 ElementProxy::~ElementProxy()
57 {
58 }
59
60 set<QName> AttributeExtensibleXMLObject::m_idAttributeSet;
61
62 AttributeExtensibleXMLObject::AttributeExtensibleXMLObject()
63 {
64 }
65
66 AttributeExtensibleXMLObject::~AttributeExtensibleXMLObject()
67 {
68 }
69
70 const set<QName>& AttributeExtensibleXMLObject::getRegisteredIDAttributes()
71 {
72     return m_idAttributeSet;
73 }
74
75 bool AttributeExtensibleXMLObject::isRegisteredIDAttribute(const QName& name)
76 {
77     return m_idAttributeSet.find(name)!=m_idAttributeSet.end();
78 }
79
80 void AttributeExtensibleXMLObject::registerIDAttribute(const QName& name)
81 {
82     m_idAttributeSet.insert(name);
83 }
84
85 void AttributeExtensibleXMLObject::deregisterIDAttribute(const QName& name)
86 {
87     m_idAttributeSet.erase(name);
88 }
89
90 void AttributeExtensibleXMLObject::deregisterIDAttributes()
91 {
92     m_idAttributeSet.clear();
93 }
94
95 AbstractAttributeExtensibleXMLObject::AbstractAttributeExtensibleXMLObject()
96 {
97     m_idAttribute = m_attributeMap.end();
98 }
99
100 AbstractAttributeExtensibleXMLObject::AbstractAttributeExtensibleXMLObject(const AbstractAttributeExtensibleXMLObject& src)
101     : AbstractXMLObject(src)
102 {
103     m_idAttribute = m_attributeMap.end();
104     for (map<QName,XMLCh*>::const_iterator i=src.m_attributeMap.begin(); i!=src.m_attributeMap.end(); i++) {
105         m_attributeMap[i->first] = XMLString::replicate(i->second);
106     }
107     if (src.m_idAttribute != src.m_attributeMap.end()) {
108         m_idAttribute = m_attributeMap.find(src.m_idAttribute->first);
109     }
110 }
111
112 AbstractAttributeExtensibleXMLObject::~AbstractAttributeExtensibleXMLObject()
113 {
114     for (map<QName,XMLCh*>::iterator i=m_attributeMap.begin(); i!=m_attributeMap.end(); i++)
115         XMLString::release(&(i->second));
116 }
117
118 const XMLCh* AbstractAttributeExtensibleXMLObject::getAttribute(const QName& qualifiedName) const
119 {
120     map<QName,XMLCh*>::const_iterator i=m_attributeMap.find(qualifiedName);
121     return (i==m_attributeMap.end()) ? nullptr : i->second;
122 }
123
124 void AbstractAttributeExtensibleXMLObject::setAttribute(const QName& qualifiedName, const XMLCh* value, bool ID)
125 {
126     map<QName,XMLCh*>::iterator i=m_attributeMap.find(qualifiedName);
127     if (i!=m_attributeMap.end()) {
128         releaseThisandParentDOM();
129         XMLString::release(&(i->second));
130         if (value && *value) {
131             i->second=XMLString::replicate(value);
132             if (ID)
133                 m_idAttribute=i;
134         }
135         else {
136             if (m_idAttribute==i)
137                 m_idAttribute=m_attributeMap.end();
138             m_attributeMap.erase(i);
139         }
140     }
141     else if (value && *value) {
142         releaseThisandParentDOM();
143         m_attributeMap[qualifiedName]=XMLString::replicate(value);
144         if (ID)
145             m_idAttribute = m_attributeMap.find(qualifiedName);
146         Namespace newNamespace(qualifiedName.getNamespaceURI(), qualifiedName.getPrefix(), false, Namespace::VisiblyUsed);
147         addNamespace(newNamespace);
148     }
149 }
150
151 void AttributeExtensibleXMLObject::setAttribute(const QName& qualifiedName, const QName& value)
152 {
153     if (!value.hasLocalPart())
154         return;
155
156     if (value.hasPrefix()) {
157         xstring buf(value.getPrefix());
158         buf = buf + chColon + value.getLocalPart();
159         setAttribute(qualifiedName, buf.c_str());
160     }
161     else {
162         setAttribute(qualifiedName, value.getLocalPart());
163     }
164
165     Namespace newNamespace(value.getNamespaceURI(), value.getPrefix(), false, Namespace::NonVisiblyUsed);
166     addNamespace(newNamespace);
167 }
168
169 const map<QName,XMLCh*>& AbstractAttributeExtensibleXMLObject::getExtensionAttributes() const
170 {
171     return m_attributeMap;
172 }
173 const XMLCh* AbstractAttributeExtensibleXMLObject::getXMLID() const
174 {
175     return (m_idAttribute == m_attributeMap.end()) ? nullptr : m_idAttribute->second;
176 }
177
178 void AbstractAttributeExtensibleXMLObject::unmarshallExtensionAttribute(const DOMAttr* attribute)
179 {
180     QName q(attribute->getNamespaceURI(),attribute->getLocalName(),attribute->getPrefix());
181     bool ID = attribute->isId() || isRegisteredIDAttribute(q);
182     setAttribute(q,attribute->getNodeValue(),ID);
183     if (ID) {
184 #ifdef XMLTOOLING_XERCESC_BOOLSETIDATTRIBUTE
185         attribute->getOwnerElement()->setIdAttributeNode(attribute, true);
186 #else
187         attribute->getOwnerElement()->setIdAttributeNode(attribute);
188 #endif
189     }
190 }
191
192 void AbstractAttributeExtensibleXMLObject::marshallExtensionAttributes(DOMElement* domElement) const
193 {
194     for (map<QName,XMLCh*>::const_iterator i=m_attributeMap.begin(); i!=m_attributeMap.end(); i++) {
195         DOMAttr* attr=domElement->getOwnerDocument()->createAttributeNS(i->first.getNamespaceURI(),i->first.getLocalPart());
196         if (i->first.hasPrefix())
197             attr->setPrefix(i->first.getPrefix());
198         attr->setNodeValue(i->second);
199         domElement->setAttributeNodeNS(attr);
200         if (m_idAttribute==i) {
201 #ifdef XMLTOOLING_XERCESC_BOOLSETIDATTRIBUTE
202             domElement->setIdAttributeNode(attr, true);
203 #else
204             domElement->setIdAttributeNode(attr);
205 #endif
206         }
207     }
208 }