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 39 CXmlElement::CXmlElement(_xmlNode *pXmlElement) : _pXmlElement(pXmlElement) 40 { 41 } 42 43 CXmlElement::CXmlElement() : _pXmlElement(nullptr) 44 { 45 } 46 47 void CXmlElement::setXmlElement(_xmlNode *pXmlElement) 48 { 49 _pXmlElement = pXmlElement; 50 } 51 52 string CXmlElement::getType() const 53 { 54 return (const char *)_pXmlElement->name; 55 } 56 57 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 76 bool CXmlElement::hasAttribute(const string &strAttributeName) const 77 { 78 return xmlHasProp(_pXmlElement, (const xmlChar *)strAttributeName.c_str()) != nullptr; 79 } 80 81 template <> 82 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> 99 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 115 string CXmlElement::getNameAttribute() const 116 { 117 string attribute; 118 getAttribute("Name", attribute); 119 return attribute; 120 } 121 122 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 136 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 150 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 166 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 180 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 <> 194 void CXmlElement::setAttribute<bool>(const string &name, const bool &value) 195 { 196 setAttribute(name, value ? "true" : "false"); 197 } 198 199 template <> 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. 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> 216 void CXmlElement::setAttribute(const std::string &name, const T &value) 217 { 218 setAttribute(name, std::to_string(value).c_str()); 219 } 220 221 void CXmlElement::setNameAttribute(const string &strValue) 222 { 223 setAttribute("Name", strValue); 224 } 225 226 void CXmlElement::setTextContent(const string &strContent) 227 { 228 xmlAddChild(_pXmlElement, xmlNewText(BAD_CAST strContent.c_str())); 229 } 230 231 // Child creation 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 242 CXmlElement::CChildIterator::CChildIterator(const CXmlElement &xmlElement) 243 : _pCurNode(xmlElement._pXmlElement->children) 244 { 245 } 246 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