Add parametrized messaging and serialization to exceptions.
[shibboleth/cpp-xmltooling.git] / xmltooling / util / XMLHelper.cpp
1 /*\r
2  *  Copyright 2001-2006 Internet2\r
3  * \r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  *     http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 \r
17 /**\r
18  * XMLHelper.cpp\r
19  * \r
20  * A helper class for working with W3C DOM objects. \r
21  */\r
22 \r
23 #include "internal.h"\r
24 #include "exceptions.h"\r
25 #include "util/XMLHelper.h"\r
26 #include "util/XMLConstants.h"\r
27 \r
28 #include <xercesc/framework/MemBufFormatTarget.hpp>\r
29 #include <xercesc/util/XMLUniDefs.hpp>\r
30 \r
31 using namespace xmltooling;\r
32 \r
33 static const XMLCh type[]={chLatin_t, chLatin_y, chLatin_p, chLatin_e, chNull };\r
34     \r
35 bool XMLHelper::hasXSIType(const DOMElement* e)\r
36 {\r
37     if (e) {\r
38         if (e->hasAttributeNS(XMLConstants::XSI_NS, type)) {\r
39             return true;\r
40         }\r
41     }\r
42 \r
43     return false;\r
44 }\r
45 \r
46 QName* XMLHelper::getXSIType(const DOMElement* e)\r
47 {\r
48     DOMAttr* attribute = e->getAttributeNodeNS(XMLConstants::XSI_NS, type);\r
49     if (attribute) {\r
50         int i;\r
51         const XMLCh* attributeValue = attribute->getTextContent();\r
52         if (attributeValue && (i=XMLString::indexOf(attributeValue,chColon))>0) {\r
53             XMLCh* prefix=new XMLCh[i+1];\r
54             XMLString::subString(prefix,attributeValue,0,i);\r
55             prefix[i]=chNull;\r
56             QName* ret=new QName(e->lookupNamespaceURI(prefix), attributeValue + i + 1, prefix);\r
57             delete[] prefix;\r
58             return ret;\r
59         }\r
60     }\r
61 \r
62     return NULL;\r
63 }\r
64 \r
65 DOMAttr* XMLHelper::getIdAttribute(const DOMElement* domElement)\r
66 {\r
67     if(!domElement->hasAttributes()) {\r
68         return NULL;\r
69     }\r
70     \r
71     DOMNamedNodeMap* attributes = domElement->getAttributes();\r
72     DOMAttr* attribute;\r
73     for(XMLSize_t i = 0; i < attributes->getLength(); i++) {\r
74         attribute = static_cast<DOMAttr*>(attributes->item(i));\r
75         if(attribute->isId()) {\r
76             return attribute;\r
77         }\r
78     }\r
79     \r
80     return NULL;\r
81 }\r
82 \r
83 QName* XMLHelper::getNodeQName(const DOMNode* domNode)\r
84 {\r
85     if (domNode)\r
86         return new QName(domNode->getNamespaceURI(), domNode->getLocalName(), domNode->getPrefix());\r
87     return NULL; \r
88 }\r
89 \r
90 QName* XMLHelper::getAttributeValueAsQName(const DOMAttr* attribute)\r
91 {\r
92     if (!attribute)\r
93         return NULL;\r
94     \r
95     int i;\r
96     const XMLCh* attributeValue=attribute->getTextContent();\r
97     if (attributeValue && (i=XMLString::indexOf(attributeValue,chColon))>0) {\r
98         XMLCh* prefix=new XMLCh[i+1];\r
99         XMLString::subString(prefix,attributeValue,0,i);\r
100         prefix[i]=chNull;\r
101         QName* ret=new QName(attribute->lookupNamespaceURI(prefix), attributeValue + i + 1, prefix);\r
102         delete[] prefix;\r
103         return ret;\r
104     }\r
105     \r
106     return new QName(attribute->lookupNamespaceURI(NULL), attributeValue);\r
107 }\r
108 \r
109 DOMElement* XMLHelper::appendChildElement(DOMElement* parentElement, DOMElement* childElement)\r
110 {\r
111     DOMDocument* parentDocument = parentElement->getOwnerDocument();\r
112     if (childElement->getOwnerDocument() != parentDocument) {\r
113         childElement = static_cast<DOMElement*>(parentDocument->importNode(childElement, true));\r
114     }\r
115 \r
116     parentElement->appendChild(childElement);\r
117     return childElement;\r
118 }\r
119 \r
120 const XMLCh* XMLHelper::getTextContent(const DOMElement* e)\r
121 {\r
122     DOMNode* child=e->getFirstChild();\r
123     while (child) {\r
124         if (child->getNodeType()==DOMNode::TEXT_NODE)\r
125             return child->getNodeValue();\r
126         child=child->getNextSibling();\r
127     }\r
128     return NULL;\r
129 }\r
130 \r
131 DOMElement* XMLHelper::getFirstChildElement(const DOMNode* n)\r
132 {\r
133     DOMNode* child = n->getFirstChild();\r
134     while (child && child->getNodeType() != DOMNode::ELEMENT_NODE)\r
135         child = child->getNextSibling();\r
136     if (child)\r
137         return static_cast<DOMElement*>(child);\r
138     return NULL;\r
139 }    \r
140 \r
141 DOMElement* XMLHelper::getLastChildElement(const DOMNode* n)\r
142 {\r
143     DOMNode* child = n->getLastChild();\r
144     while (child && child->getNodeType() != DOMNode::ELEMENT_NODE)\r
145         child = child->getPreviousSibling();\r
146     if (child)\r
147         return static_cast<DOMElement*>(child);\r
148     return NULL;\r
149 }    \r
150 \r
151 DOMElement* XMLHelper::getFirstChildElement(const DOMNode* n, const XMLCh* ns, const XMLCh* localName)\r
152 {\r
153     DOMElement* e = getFirstChildElement(n);\r
154     while (e && !isNodeNamed(e, ns, localName))\r
155         e = getNextSiblingElement(e);\r
156     return e;\r
157 }\r
158 \r
159 DOMElement* XMLHelper::getLastChildElement(const DOMNode* n, const XMLCh* ns, const XMLCh* localName)\r
160 {\r
161     DOMElement* e = getLastChildElement(n);\r
162     while (e && !isNodeNamed(e, ns, localName))\r
163         e = getPreviousSiblingElement(e);\r
164     return e;\r
165 }\r
166 \r
167 DOMElement* XMLHelper::getNextSiblingElement(const DOMNode* n)\r
168 {\r
169     DOMNode* sib = n->getNextSibling();\r
170     while (sib && sib->getNodeType() != DOMNode::ELEMENT_NODE)\r
171         sib = sib->getNextSibling();\r
172     if (sib)\r
173         return static_cast<DOMElement*>(sib);\r
174     return NULL;\r
175 }\r
176 \r
177 DOMElement* XMLHelper::getPreviousSiblingElement(const DOMNode* n)\r
178 {\r
179     DOMNode* sib = n->getPreviousSibling();\r
180     while (sib && sib->getNodeType() != DOMNode::ELEMENT_NODE)\r
181         sib = sib->getPreviousSibling();\r
182     if (sib)\r
183         return static_cast<DOMElement*>(sib);\r
184     return NULL;\r
185 }\r
186 \r
187 DOMElement* XMLHelper::getNextSiblingElement(const DOMNode* n, const XMLCh* ns, const XMLCh* localName)\r
188 {\r
189     DOMElement* e = getNextSiblingElement(n);\r
190     while (e && !isNodeNamed(e, ns, localName))\r
191         e = getNextSiblingElement(e);\r
192     return e;\r
193 }\r
194 \r
195 DOMElement* XMLHelper::getPreviousSiblingElement(const DOMNode* n, const XMLCh* ns, const XMLCh* localName)\r
196 {\r
197     DOMElement* e = getPreviousSiblingElement(n);\r
198     while (e && !isNodeNamed(e, ns, localName))\r
199         e = getPreviousSiblingElement(e);\r
200     return e;\r
201 }\r
202 \r
203 void XMLHelper::serialize(const DOMElement* e, std::string& buf)\r
204 {\r
205     static const XMLCh impltype[] = { chLatin_L, chLatin_S, chNull };\r
206     static const XMLCh UTF8[]={ chLatin_U, chLatin_T, chLatin_F, chDigit_8, chNull };\r
207     DOMImplementation* impl=DOMImplementationRegistry::getDOMImplementation(impltype);\r
208     DOMWriter* serializer=(static_cast<DOMImplementationLS*>(impl))->createDOMWriter();\r
209     serializer->setEncoding(UTF8);\r
210     try {\r
211         MemBufFormatTarget target;\r
212         if (!serializer->writeNode(&target,*e))\r
213             throw XMLParserException("unable to serialize XML");\r
214         buf.erase();\r
215         buf.append(reinterpret_cast<const char*>(target.getRawBuffer()),target.getLen());\r
216         serializer->release();\r
217     }\r
218     catch (...) {\r
219         serializer->release();\r
220         throw;\r
221     }\r
222 }\r