Distinguish between visibly used and unused namespaces.
[shibboleth/cpp-xmltooling.git] / xmltooling / AbstractAttributeExtensibleXMLObject.cpp
1 /*
2  *  Copyright 2001-2010 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  * AbstractAttributeExtensibleXMLObject.cpp
19  * 
20  * Extension of AbstractDOMCachingXMLObject that implements an AttributeExtensibleXMLObject. 
21  */
22
23 #include "internal.h"
24 #include "AbstractAttributeExtensibleXMLObject.h"
25 #include "ElementExtensibleXMLObject.h"
26 #include "ElementProxy.h"
27
28 #include <algorithm>
29 #include <functional>
30
31 using namespace xmltooling;
32 using namespace std;
33 using xercesc::chColon;
34
35 using xercesc::DOMAttr;
36 using xercesc::DOMElement;
37 using xercesc::XMLString;
38
39 ElementExtensibleXMLObject::ElementExtensibleXMLObject()
40 {
41 }
42
43 ElementExtensibleXMLObject::~ElementExtensibleXMLObject()
44 {
45 }
46
47 ElementProxy::ElementProxy()
48 {
49 }
50
51 ElementProxy::~ElementProxy()
52 {
53 }
54
55 set<QName> AttributeExtensibleXMLObject::m_idAttributeSet;
56
57 AttributeExtensibleXMLObject::AttributeExtensibleXMLObject()
58 {
59 }
60
61 AttributeExtensibleXMLObject::~AttributeExtensibleXMLObject()
62 {
63 }
64
65 const set<QName>& AttributeExtensibleXMLObject::getRegisteredIDAttributes()
66 {
67     return m_idAttributeSet;
68 }
69
70 bool AttributeExtensibleXMLObject::isRegisteredIDAttribute(const QName& name)
71 {
72     return m_idAttributeSet.find(name)!=m_idAttributeSet.end();
73 }
74
75 void AttributeExtensibleXMLObject::registerIDAttribute(const QName& name)
76 {
77     m_idAttributeSet.insert(name);
78 }
79
80 void AttributeExtensibleXMLObject::deregisterIDAttribute(const QName& name)
81 {
82     m_idAttributeSet.erase(name);
83 }
84
85 void AttributeExtensibleXMLObject::deregisterIDAttributes()
86 {
87     m_idAttributeSet.clear();
88 }
89
90 AbstractAttributeExtensibleXMLObject::AbstractAttributeExtensibleXMLObject()
91 {
92     m_idAttribute = m_attributeMap.end();
93 }
94
95 AbstractAttributeExtensibleXMLObject::AbstractAttributeExtensibleXMLObject(const AbstractAttributeExtensibleXMLObject& src)
96     : AbstractXMLObject(src)
97 {
98     m_idAttribute = m_attributeMap.end();
99     for (map<QName,XMLCh*>::const_iterator i=src.m_attributeMap.begin(); i!=src.m_attributeMap.end(); i++) {
100         m_attributeMap[i->first] = XMLString::replicate(i->second);
101     }
102     if (src.m_idAttribute != src.m_attributeMap.end()) {
103         m_idAttribute = m_attributeMap.find(src.m_idAttribute->first);
104     }
105 }
106
107 AbstractAttributeExtensibleXMLObject::~AbstractAttributeExtensibleXMLObject()
108 {
109     for (map<QName,XMLCh*>::iterator i=m_attributeMap.begin(); i!=m_attributeMap.end(); i++)
110         XMLString::release(&(i->second));
111 }
112
113 const XMLCh* AbstractAttributeExtensibleXMLObject::getAttribute(const QName& qualifiedName) const
114 {
115     map<QName,XMLCh*>::const_iterator i=m_attributeMap.find(qualifiedName);
116     return (i==m_attributeMap.end()) ? NULL : i->second;
117 }
118
119 void AbstractAttributeExtensibleXMLObject::setAttribute(const QName& qualifiedName, const XMLCh* value, bool ID)
120 {
121     map<QName,XMLCh*>::iterator i=m_attributeMap.find(qualifiedName);
122     if (i!=m_attributeMap.end()) {
123         releaseThisandParentDOM();
124         XMLString::release(&(i->second));
125         if (value && *value) {
126             i->second=XMLString::replicate(value);
127             if (ID)
128                 m_idAttribute=i;
129         }
130         else {
131             if (m_idAttribute==i)
132                 m_idAttribute=m_attributeMap.end();
133             m_attributeMap.erase(i);
134         }
135     }
136     else if (value && *value) {
137         releaseThisandParentDOM();
138         m_attributeMap[qualifiedName]=XMLString::replicate(value);
139         if (ID)
140             m_idAttribute = m_attributeMap.find(qualifiedName);
141         Namespace newNamespace(qualifiedName.getNamespaceURI(), qualifiedName.getPrefix());
142         addNamespace(newNamespace);
143     }
144 }
145
146 void AttributeExtensibleXMLObject::setAttribute(const QName& qualifiedName, const QName& value)
147 {
148     if (!value.hasLocalPart())
149         return;
150
151     if (value.hasPrefix()) {
152         xstring buf(value.getPrefix());
153         buf = buf + chColon + value.getLocalPart();
154         setAttribute(qualifiedName, buf.c_str());
155     }
156     else {
157         setAttribute(qualifiedName, value.getLocalPart());
158     }
159
160     // Attach a non-visibly used namespace.
161     Namespace newNamespace(value.getNamespaceURI(), value.getPrefix(), false, false);
162     addNamespace(newNamespace);
163 }
164
165 const map<QName,XMLCh*>& AbstractAttributeExtensibleXMLObject::getExtensionAttributes() const
166 {
167     return m_attributeMap;
168 }
169 const XMLCh* AbstractAttributeExtensibleXMLObject::getXMLID() const
170 {
171     return (m_idAttribute == m_attributeMap.end()) ? NULL : m_idAttribute->second;
172 }
173
174 void AbstractAttributeExtensibleXMLObject::unmarshallExtensionAttribute(const DOMAttr* attribute)
175 {
176     QName q(attribute->getNamespaceURI(),attribute->getLocalName(),attribute->getPrefix());
177     bool ID = attribute->isId() || isRegisteredIDAttribute(q);
178     setAttribute(q,attribute->getNodeValue(),ID);
179     if (ID) {
180 #ifdef XMLTOOLING_XERCESC_BOOLSETIDATTRIBUTE
181         attribute->getOwnerElement()->setIdAttributeNode(attribute, true);
182 #else
183         attribute->getOwnerElement()->setIdAttributeNode(attribute);
184 #endif
185     }
186 }
187
188 void AbstractAttributeExtensibleXMLObject::marshallExtensionAttributes(DOMElement* domElement) const
189 {
190     for (map<QName,XMLCh*>::const_iterator i=m_attributeMap.begin(); i!=m_attributeMap.end(); i++) {
191         DOMAttr* attr=domElement->getOwnerDocument()->createAttributeNS(i->first.getNamespaceURI(),i->first.getLocalPart());
192         if (i->first.hasPrefix())
193             attr->setPrefix(i->first.getPrefix());
194         attr->setNodeValue(i->second);
195         domElement->setAttributeNodeNS(attr);
196         if (m_idAttribute==i) {
197 #ifdef XMLTOOLING_XERCESC_BOOLSETIDATTRIBUTE
198             domElement->setIdAttributeNode(attr, true);
199 #else
200             domElement->setIdAttributeNode(attr);
201 #endif
202         }
203     }
204 }