1 /*
2 * Copyright (c) 2011-2014, Intel Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation and/or
13 * other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors
16 * may be used to endorse or promote products derived from this software without
17 * specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #include "XmlElement.h"
31 #include "PfError.hpp"
32 #include <libxml/tree.h>
33 #include "convert.hpp"
34 #include <stdlib.h>
35 #include <stdexcept>
36
37 using std::string;
38
CXmlElement(_xmlNode * pXmlElement)39 CXmlElement::CXmlElement(_xmlNode *pXmlElement) : _pXmlElement(pXmlElement)
40 {
41 }
42
CXmlElement()43 CXmlElement::CXmlElement() : _pXmlElement(nullptr)
44 {
45 }
46
setXmlElement(_xmlNode * pXmlElement)47 void CXmlElement::setXmlElement(_xmlNode *pXmlElement)
48 {
49 _pXmlElement = pXmlElement;
50 }
51
getType() const52 string CXmlElement::getType() const
53 {
54 return (const char *)_pXmlElement->name;
55 }
56
getPath() const57 string CXmlElement::getPath() const
58 {
59 string strPathElement = "/" + getType();
60
61 if (hasAttribute("Name")) {
62
63 strPathElement += "[@Name=" + getNameAttribute() + "]";
64 }
65
66 CXmlElement parentElement;
67
68 if (getParentElement(parentElement)) {
69
70 // Done
71 return parentElement.getPath() + strPathElement;
72 }
73 return strPathElement;
74 }
75
hasAttribute(const string & strAttributeName) const76 bool CXmlElement::hasAttribute(const string &strAttributeName) const
77 {
78 return xmlHasProp(_pXmlElement, (const xmlChar *)strAttributeName.c_str()) != nullptr;
79 }
80
81 template <>
getAttribute(const string & name,string & value) const82 bool CXmlElement::getAttribute<std::string>(const string &name, string &value) const
83 {
84 string backup = value;
85 xmlChar *pucXmlValue = xmlGetProp((xmlNode *)_pXmlElement, (const xmlChar *)name.c_str());
86 if (pucXmlValue == nullptr) {
87 value = backup;
88 return false;
89 }
90
91 value = (const char *)pucXmlValue;
92
93 xmlFree(pucXmlValue);
94
95 return true;
96 }
97
98 template <typename T>
getAttribute(const std::string & name,T & value) const99 bool CXmlElement::getAttribute(const std::string &name, T &value) const
100 {
101 std::string rawValue;
102 if (!getAttribute(name, rawValue)) {
103 return false;
104 }
105
106 T backup = value;
107 if (!convertTo<T>(rawValue, value)) {
108 value = backup;
109 throw PfError("\'" + rawValue + "\' could not be parsed as the requested type.");
110 }
111
112 return true;
113 }
114
getNameAttribute() const115 string CXmlElement::getNameAttribute() const
116 {
117 string attribute;
118 getAttribute("Name", attribute);
119 return attribute;
120 }
121
getTextContent() const122 string CXmlElement::getTextContent() const
123 {
124 xmlChar *pucXmlContent = xmlNodeGetContent(_pXmlElement);
125 if (pucXmlContent == nullptr) {
126 return "";
127 }
128
129 string strContent((const char *)pucXmlContent);
130
131 xmlFree(pucXmlContent);
132
133 return strContent;
134 }
135
getChildElement(const string & strType,CXmlElement & childElement) const136 bool CXmlElement::getChildElement(const string &strType, CXmlElement &childElement) const
137 {
138 CChildIterator childIterator(*this);
139
140 while (childIterator.next(childElement)) {
141
142 if (childElement.getType() == strType) {
143
144 return true;
145 }
146 }
147 return false;
148 }
149
getChildElement(const string & strType,const string & strNameAttribute,CXmlElement & childElement) const150 bool CXmlElement::getChildElement(const string &strType, const string &strNameAttribute,
151 CXmlElement &childElement) const
152 {
153 CChildIterator childIterator(*this);
154
155 while (childIterator.next(childElement)) {
156
157 if ((childElement.getType() == strType) &&
158 (childElement.getNameAttribute() == strNameAttribute)) {
159
160 return true;
161 }
162 }
163 return false;
164 }
165
getNbChildElements() const166 size_t CXmlElement::getNbChildElements() const
167 {
168 CXmlElement childElement;
169 size_t uiNbChildren = 0;
170
171 CChildIterator childIterator(*this);
172
173 while (childIterator.next(childElement)) {
174
175 uiNbChildren++;
176 }
177 return uiNbChildren;
178 }
179
getParentElement(CXmlElement & parentElement) const180 bool CXmlElement::getParentElement(CXmlElement &parentElement) const
181 {
182 _xmlNode *pXmlNode = _pXmlElement->parent;
183
184 if (pXmlNode->type == XML_ELEMENT_NODE) {
185
186 parentElement.setXmlElement(pXmlNode);
187
188 return true;
189 }
190 return false;
191 }
192
193 template <>
setAttribute(const string & name,const bool & value)194 void CXmlElement::setAttribute<bool>(const string &name, const bool &value)
195 {
196 setAttribute(name, value ? "true" : "false");
197 }
198
199 template <>
setAttribute(const string & name,const string & value)200 void CXmlElement::setAttribute<std::string>(const string &name, const string &value)
201 {
202 setAttribute(name, value.c_str());
203 }
204
205 // This method exists for 2 reasons:
206 // - at link time, all calls to setAttribute(const string&, const char [N])
207 // for any value of N will all resolve to this method; this prevents the
208 // need for one template instance per value of N.
209 // - the libxml2 API takes a C-style string anyway.
setAttribute(const string & name,const char * value)210 void CXmlElement::setAttribute(const string &name, const char *value)
211 {
212 xmlNewProp(_pXmlElement, BAD_CAST name.c_str(), BAD_CAST value);
213 }
214
215 template <typename T>
setAttribute(const std::string & name,const T & value)216 void CXmlElement::setAttribute(const std::string &name, const T &value)
217 {
218 setAttribute(name, std::to_string(value).c_str());
219 }
220
setNameAttribute(const string & strValue)221 void CXmlElement::setNameAttribute(const string &strValue)
222 {
223 setAttribute("Name", strValue);
224 }
225
setTextContent(const string & strContent)226 void CXmlElement::setTextContent(const string &strContent)
227 {
228 xmlAddChild(_pXmlElement, xmlNewText(BAD_CAST strContent.c_str()));
229 }
230
231 // Child creation
createChild(CXmlElement & childElement,const string & strType)232 void CXmlElement::createChild(CXmlElement &childElement, const string &strType)
233 {
234 #ifdef LIBXML_TREE_ENABLED
235 xmlNodePtr pChildNode = xmlNewChild(_pXmlElement, nullptr, BAD_CAST strType.c_str(), nullptr);
236
237 childElement.setXmlElement(pChildNode);
238 #endif
239 }
240
241 // Child iteration
CChildIterator(const CXmlElement & xmlElement)242 CXmlElement::CChildIterator::CChildIterator(const CXmlElement &xmlElement)
243 : _pCurNode(xmlElement._pXmlElement->children)
244 {
245 }
246
next(CXmlElement & xmlChildElement)247 bool CXmlElement::CChildIterator::next(CXmlElement &xmlChildElement)
248 {
249 while (_pCurNode) {
250
251 if (_pCurNode->type == XML_ELEMENT_NODE) {
252
253 xmlChildElement.setXmlElement(_pCurNode);
254
255 _pCurNode = _pCurNode->next;
256
257 return true;
258 }
259 _pCurNode = _pCurNode->next;
260 }
261
262 return false;
263 }
264
265 template bool CXmlElement::getAttribute(const std::string &name, bool &value) const;
266 template bool CXmlElement::getAttribute(const std::string &name, signed char &value) const;
267 template bool CXmlElement::getAttribute(const std::string &name, unsigned char &value) const;
268 template bool CXmlElement::getAttribute(const std::string &name, short &value) const;
269 template bool CXmlElement::getAttribute(const std::string &name, unsigned short &value) const;
270 template bool CXmlElement::getAttribute(const std::string &name, int &value) const;
271 template bool CXmlElement::getAttribute(const std::string &name, unsigned int &value) const;
272 template bool CXmlElement::getAttribute(const std::string &name, long &value) const;
273 template bool CXmlElement::getAttribute(const std::string &name, unsigned long &value) const;
274 template bool CXmlElement::getAttribute(const std::string &name, long long &value) const;
275 template bool CXmlElement::getAttribute(const std::string &name, unsigned long long &value) const;
276 template bool CXmlElement::getAttribute(const std::string &name, float &value) const;
277 template bool CXmlElement::getAttribute(const std::string &name, double &value) const;
278
279 template void CXmlElement::setAttribute(const std::string &name, const signed char &value);
280 template void CXmlElement::setAttribute(const std::string &name, const unsigned char &value);
281 template void CXmlElement::setAttribute(const std::string &name, const short &value);
282 template void CXmlElement::setAttribute(const std::string &name, const unsigned short &value);
283 template void CXmlElement::setAttribute(const std::string &name, const int &value);
284 template void CXmlElement::setAttribute(const std::string &name, const unsigned int &value);
285 template void CXmlElement::setAttribute(const std::string &name, const long &value);
286 template void CXmlElement::setAttribute(const std::string &name, const unsigned long &value);
287 template void CXmlElement::setAttribute(const std::string &name, const long long &value);
288 template void CXmlElement::setAttribute(const std::string &name, const unsigned long long &value);
289 template void CXmlElement::setAttribute(const std::string &name, const float &value);
290 template void CXmlElement::setAttribute(const std::string &name, const double &value);
291