Add credential context APIs, refactor criteria matching, auto-extract criteria from...
[shibboleth/cpp-xmltooling.git] / xmltooling / util / XMLHelper.cpp
1 /*
2  *  Copyright 2001-2007 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  * XMLHelper.cpp
19  * 
20  * A helper class for working with W3C DOM objects. 
21  */
22
23 #include "internal.h"
24 #include "exceptions.h"
25 #include "util/XMLHelper.h"
26 #include "util/XMLConstants.h"
27
28 #include <xercesc/framework/MemBufFormatTarget.hpp>
29 #include <xercesc/util/XMLUniDefs.hpp>
30
31 using namespace xmltooling;
32 using namespace std;
33
34 static const XMLCh type[]={chLatin_t, chLatin_y, chLatin_p, chLatin_e, chNull };
35     
36 bool XMLHelper::hasXSIType(const DOMElement* e)
37 {
38     if (e) {
39         if (e->hasAttributeNS(xmlconstants::XSI_NS, type)) {
40             return true;
41         }
42     }
43
44     return false;
45 }
46
47 QName* XMLHelper::getXSIType(const DOMElement* e)
48 {
49     DOMAttr* attribute = e->getAttributeNodeNS(xmlconstants::XSI_NS, type);
50     if (attribute) {
51         const XMLCh* attributeValue = attribute->getTextContent();
52         if (attributeValue && *attributeValue) {
53             int i;
54             if ((i=XMLString::indexOf(attributeValue,chColon))>0) {
55                 XMLCh* prefix=new XMLCh[i+1];
56                 XMLString::subString(prefix,attributeValue,0,i);
57                 prefix[i]=chNull;
58                 QName* ret=new QName(e->lookupNamespaceURI(prefix), attributeValue + i + 1, prefix);
59                 delete[] prefix;
60                 return ret;
61             }
62             else {
63                 return new QName(e->lookupNamespaceURI(&chNull), attributeValue);
64             }
65         }
66     }
67
68     return NULL;
69 }
70
71 DOMAttr* XMLHelper::getIdAttribute(const DOMElement* domElement)
72 {
73     if(!domElement->hasAttributes()) {
74         return NULL;
75     }
76     
77     DOMNamedNodeMap* attributes = domElement->getAttributes();
78     DOMAttr* attribute;
79     for(XMLSize_t i = 0; i < attributes->getLength(); i++) {
80         attribute = static_cast<DOMAttr*>(attributes->item(i));
81         if(attribute->isId()) {
82             return attribute;
83         }
84     }
85     
86     return NULL;
87 }
88
89 const XMLObject* XMLHelper::getXMLObjectById(const XMLObject& tree, const XMLCh* id)
90 {
91     if (XMLString::equals(id, tree.getXMLID()))
92         return &tree;
93     
94     const XMLObject* ret;
95     const list<XMLObject*>& children = tree.getOrderedChildren();
96     for (list<XMLObject*>::const_iterator i=children.begin(); i!=children.end(); ++i) {
97         if (*i) {
98             ret = getXMLObjectById(*(*i), id);
99             if (ret)
100                 return ret;
101         }
102     }
103     
104     return NULL;
105 }
106
107 QName* XMLHelper::getNodeQName(const DOMNode* domNode)
108 {
109     if (domNode)
110         return new QName(domNode->getNamespaceURI(), domNode->getLocalName(), domNode->getPrefix());
111     return NULL; 
112 }
113
114 QName* XMLHelper::getAttributeValueAsQName(const DOMAttr* attribute)
115 {
116     if (!attribute)
117         return NULL;
118     
119     int i;
120     const XMLCh* attributeValue=attribute->getTextContent();
121     if (attributeValue && (i=XMLString::indexOf(attributeValue,chColon))>0) {
122         XMLCh* prefix=new XMLCh[i+1];
123         XMLString::subString(prefix,attributeValue,0,i);
124         prefix[i]=chNull;
125         QName* ret=new QName(attribute->lookupNamespaceURI(prefix), attributeValue + i + 1, prefix);
126         delete[] prefix;
127         return ret;
128     }
129     
130     return new QName(attribute->lookupNamespaceURI(NULL), attributeValue);
131 }
132
133 DOMElement* XMLHelper::appendChildElement(DOMElement* parentElement, DOMElement* childElement)
134 {
135     DOMDocument* parentDocument = parentElement->getOwnerDocument();
136     if (childElement->getOwnerDocument() != parentDocument) {
137         childElement = static_cast<DOMElement*>(parentDocument->importNode(childElement, true));
138     }
139
140     parentElement->appendChild(childElement);
141     return childElement;
142 }
143
144 const XMLCh* XMLHelper::getTextContent(const DOMElement* e)
145 {
146     DOMNode* child=e->getFirstChild();
147     while (child) {
148         if (child->getNodeType()==DOMNode::TEXT_NODE)
149             return child->getNodeValue();
150         child=child->getNextSibling();
151     }
152     return NULL;
153 }
154
155 DOMElement* XMLHelper::getFirstChildElement(const DOMNode* n, const XMLCh* localName)
156 {
157     DOMNode* child = n->getFirstChild();
158     while (child && child->getNodeType() != DOMNode::ELEMENT_NODE)
159         child = child->getNextSibling();
160     if (child && localName) {
161         if (!XMLString::equals(localName,child->getLocalName()))
162             return getNextSiblingElement(child, localName);
163     }
164     return static_cast<DOMElement*>(child);
165 }    
166
167 DOMElement* XMLHelper::getLastChildElement(const DOMNode* n, const XMLCh* localName)
168 {
169     DOMNode* child = n->getLastChild();
170     while (child && child->getNodeType() != DOMNode::ELEMENT_NODE)
171         child = child->getPreviousSibling();
172     if (child && localName) {
173         if (!XMLString::equals(localName,child->getLocalName()))
174             return getPreviousSiblingElement(child, localName);
175     }
176     return static_cast<DOMElement*>(child);
177 }    
178
179 DOMElement* XMLHelper::getFirstChildElement(const DOMNode* n, const XMLCh* ns, const XMLCh* localName)
180 {
181     DOMElement* e = getFirstChildElement(n, localName);
182     while (e && !XMLString::equals(e->getNamespaceURI(),ns))
183         e = getNextSiblingElement(e, localName);
184     return e;
185 }
186
187 DOMElement* XMLHelper::getLastChildElement(const DOMNode* n, const XMLCh* ns, const XMLCh* localName)
188 {
189     DOMElement* e = getLastChildElement(n, localName);
190     while (e && !XMLString::equals(e->getNamespaceURI(),ns))
191         e = getPreviousSiblingElement(e, localName);
192     return e;
193 }
194
195 DOMElement* XMLHelper::getNextSiblingElement(const DOMNode* n, const XMLCh* localName)
196 {
197     DOMNode* sib = n->getNextSibling();
198     while (sib && sib->getNodeType() != DOMNode::ELEMENT_NODE)
199         sib = sib->getNextSibling();
200     if (sib && localName) {
201         if (!XMLString::equals(localName,sib->getLocalName()))
202             return getNextSiblingElement(sib, localName);
203     }   
204     return static_cast<DOMElement*>(sib);
205 }
206
207 DOMElement* XMLHelper::getPreviousSiblingElement(const DOMNode* n, const XMLCh* localName)
208 {
209     DOMNode* sib = n->getPreviousSibling();
210     while (sib && sib->getNodeType() != DOMNode::ELEMENT_NODE)
211         sib = sib->getPreviousSibling();
212     if (sib && localName) {
213         if (!XMLString::equals(localName,sib->getLocalName()))
214             return getPreviousSiblingElement(sib, localName);
215     }   
216     return static_cast<DOMElement*>(sib);
217 }
218
219 DOMElement* XMLHelper::getNextSiblingElement(const DOMNode* n, const XMLCh* ns, const XMLCh* localName)
220 {
221     DOMElement* e = getNextSiblingElement(n, localName);
222     while (e && !XMLString::equals(e->getNamespaceURI(),ns))
223         e = getNextSiblingElement(e, localName);
224     return e;
225 }
226
227 DOMElement* XMLHelper::getPreviousSiblingElement(const DOMNode* n, const XMLCh* ns, const XMLCh* localName)
228 {
229     DOMElement* e = getPreviousSiblingElement(n, localName);
230     while (e && !XMLString::equals(e->getNamespaceURI(),ns))
231         e = getPreviousSiblingElement(e, localName);
232     return e;
233 }
234
235 void XMLHelper::serialize(const DOMNode* n, std::string& buf)
236 {
237     static const XMLCh impltype[] = { chLatin_L, chLatin_S, chNull };
238     static const XMLCh UTF8[]={ chLatin_U, chLatin_T, chLatin_F, chDigit_8, chNull };
239     DOMImplementation* impl=DOMImplementationRegistry::getDOMImplementation(impltype);
240     DOMWriter* serializer=(static_cast<DOMImplementationLS*>(impl))->createDOMWriter();
241     XercesJanitor<DOMWriter> janitor(serializer);
242     serializer->setEncoding(UTF8);
243     MemBufFormatTarget target;
244     if (!serializer->writeNode(&target,*n))
245         throw XMLParserException("unable to serialize XML");
246     buf.erase();
247     buf.append(reinterpret_cast<const char*>(target.getRawBuffer()),target.getLen());
248 }
249
250 namespace {
251     class StreamFormatTarget : public XMLFormatTarget
252     {
253     public:
254         StreamFormatTarget(std::ostream& out) : m_out(out) {}
255         ~StreamFormatTarget() {}
256
257         void writeChars(const XMLByte *const toWrite, const unsigned int count, XMLFormatter *const formatter) {
258             m_out.write(reinterpret_cast<const char*>(toWrite),count);
259         }
260
261         void flush() {
262             m_out.flush();
263         }
264
265     private:
266         std::ostream& m_out;
267     };
268 };
269
270 ostream& XMLHelper::serialize(const DOMNode* n, ostream& out)
271 {
272     static const XMLCh impltype[] = { chLatin_L, chLatin_S, chNull };
273     static const XMLCh UTF8[]={ chLatin_U, chLatin_T, chLatin_F, chDigit_8, chNull };
274     DOMImplementation* impl=DOMImplementationRegistry::getDOMImplementation(impltype);
275     DOMWriter* serializer=(static_cast<DOMImplementationLS*>(impl))->createDOMWriter();
276     XercesJanitor<DOMWriter> janitor(serializer);
277     serializer->setEncoding(UTF8);
278     StreamFormatTarget target(out);
279     if (!serializer->writeNode(&target,*n))
280         throw XMLParserException("unable to serialize XML");
281     return out;
282 }
283
284 ostream& xmltooling::operator<<(ostream& ostr, const DOMNode& node)
285 {
286     return XMLHelper::serialize(&node, ostr);
287 }
288
289 ostream& xmltooling::operator<<(ostream& ostr, const XMLObject& obj)
290 {
291     return ostr << *(obj.marshall());
292 }