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 <libxml/tree.h> 32 #include "convert.hpp" 33 #include <stdlib.h> 34 35 using std::string; 36 37 CXmlElement::CXmlElement(_xmlNode *pXmlElement) : _pXmlElement(pXmlElement) 38 { 39 } 40 41 CXmlElement::CXmlElement() : _pXmlElement(NULL) 42 { 43 } 44 45 void CXmlElement::setXmlElement(_xmlNode *pXmlElement) 46 { 47 _pXmlElement = pXmlElement; 48 } 49 50 string CXmlElement::getType() const 51 { 52 return (const char *)_pXmlElement->name; 53 } 54 55 string CXmlElement::getPath() const 56 { 57 string strPathElement = "/" + getType(); 58 59 if (hasAttribute("Name")) { 60 61 strPathElement += "[@Name=" + getNameAttribute() + "]"; 62 } 63 64 CXmlElement parentElement; 65 66 if (getParentElement(parentElement)) { 67 68 // Done 69 return parentElement.getPath() + strPathElement; 70 } 71 return strPathElement; 72 } 73 74 bool CXmlElement::hasAttribute(const string &strAttributeName) const 75 { 76 return xmlHasProp(_pXmlElement, (const xmlChar *)strAttributeName.c_str()) != NULL; 77 } 78 79 template <> 80 bool CXmlElement::getAttribute<std::string>(const string &name, string &value) const 81 { 82 if (!hasAttribute(name)) { 83 return false; 84 } 85 86 string backup = value; 87 xmlChar *pucXmlValue = xmlGetProp((xmlNode *)_pXmlElement, (const xmlChar *)name.c_str()); 88 if (pucXmlValue == NULL) { 89 value = backup; 90 return false; 91 } 92 93 value = (const char *)pucXmlValue; 94 95 xmlFree(pucXmlValue); 96 97 return true; 98 } 99 100 template <typename T> 101 bool CXmlElement::getAttribute(const std::string &name, T &value) const 102 { 103 std::string rawValue; 104 if (!getAttribute(name, rawValue)) { 105 return false; 106 } 107 108 T backup = value; 109 if (!convertTo<T>(rawValue, value)) { 110 value = backup; 111 return false; 112 } 113 114 return true; 115 } 116 117 string CXmlElement::getNameAttribute() const 118 { 119 string attribute; 120 getAttribute("Name", attribute); 121 return attribute; 122 } 123 124 string CXmlElement::getTextContent() const 125 { 126 xmlChar *pucXmlContent = xmlNodeGetContent(_pXmlElement); 127 if (pucXmlContent == NULL) { 128 return ""; 129 } 130 131 string strContent((const char *)pucXmlContent); 132 133 xmlFree(pucXmlContent); 134 135 return strContent; 136 } 137 138 bool CXmlElement::getChildElement(const string &strType, CXmlElement &childElement) const 139 { 140 CChildIterator childIterator(*this); 141 142 while (childIterator.next(childElement)) { 143 144 if (childElement.getType() == strType) { 145 146 return true; 147 } 148 } 149 return false; 150 } 151 152 bool CXmlElement::getChildElement(const string &strType, const string &strNameAttribute, 153 CXmlElement &childElement) const 154 { 155 CChildIterator childIterator(*this); 156 157 while (childIterator.next(childElement)) { 158 159 if ((childElement.getType() == strType) && 160 (childElement.getNameAttribute() == strNameAttribute)) { 161 162 return true; 163 } 164 } 165 return false; 166 } 167 168 size_t CXmlElement::getNbChildElements() const 169 { 170 CXmlElement childElement; 171 size_t uiNbChildren = 0; 172 173 CChildIterator childIterator(*this); 174 175 while (childIterator.next(childElement)) { 176 177 uiNbChildren++; 178 } 179 return uiNbChildren; 180 } 181 182 bool CXmlElement::getParentElement(CXmlElement &parentElement) const 183 { 184 _xmlNode *pXmlNode = _pXmlElement->parent; 185 186 if (pXmlNode->type == XML_ELEMENT_NODE) { 187 188 parentElement.setXmlElement(pXmlNode); 189 190 return true; 191 } 192 return false; 193 } 194 195 template <> 196 void CXmlElement::setAttribute<bool>(const string &name, const bool &value) 197 { 198 setAttribute(name, value ? "true" : "false"); 199 } 200 201 template <> 202 void CXmlElement::setAttribute<std::string>(const string &name, const string &value) 203 { 204 setAttribute(name, value.c_str()); 205 } 206 207 // This method exists for 2 reasons: 208 // - at link time, all calls to setAttribute(const string&, const char [N]) 209 // for any value of N will all resolve to this method; this prevents the 210 // need for one template instance per value of N. 211 // - the libxml2 API takes a C-style string anyway. 212 void CXmlElement::setAttribute(const string &name, const char *value) 213 { 214 xmlNewProp(_pXmlElement, BAD_CAST name.c_str(), BAD_CAST value); 215 } 216 217 template <typename T> 218 void CXmlElement::setAttribute(const std::string &name, const T &value) 219 { 220 setAttribute(name, std::to_string(value).c_str()); 221 } 222 223 void CXmlElement::setNameAttribute(const string &strValue) 224 { 225 setAttribute("Name", strValue); 226 } 227 228 void CXmlElement::setTextContent(const string &strContent) 229 { 230 xmlAddChild(_pXmlElement, xmlNewText(BAD_CAST strContent.c_str())); 231 } 232 233 // Child creation 234 void CXmlElement::createChild(CXmlElement &childElement, const string &strType) 235 { 236 #ifdef LIBXML_TREE_ENABLED 237 xmlNodePtr pChildNode = xmlNewChild(_pXmlElement, NULL, BAD_CAST strType.c_str(), NULL); 238 239 childElement.setXmlElement(pChildNode); 240 #endif 241 } 242 243 // Child iteration 244 CXmlElement::CChildIterator::CChildIterator(const CXmlElement &xmlElement) 245 : _pCurNode(xmlElement._pXmlElement->children) 246 { 247 } 248 249 bool CXmlElement::CChildIterator::next(CXmlElement &xmlChildElement) 250 { 251 while (_pCurNode) { 252 253 if (_pCurNode->type == XML_ELEMENT_NODE) { 254 255 xmlChildElement.setXmlElement(_pCurNode); 256 257 _pCurNode = _pCurNode->next; 258 259 return true; 260 } 261 _pCurNode = _pCurNode->next; 262 } 263 264 return false; 265 } 266 267 template bool CXmlElement::getAttribute(const std::string &name, std::string &value) const; 268 template bool CXmlElement::getAttribute(const std::string &name, bool &value) const; 269 template bool CXmlElement::getAttribute(const std::string &name, short &value) const; 270 template bool CXmlElement::getAttribute(const std::string &name, unsigned short &value) const; 271 template bool CXmlElement::getAttribute(const std::string &name, int &value) const; 272 template bool CXmlElement::getAttribute(const std::string &name, unsigned int &value) const; 273 template bool CXmlElement::getAttribute(const std::string &name, long &value) const; 274 template bool CXmlElement::getAttribute(const std::string &name, unsigned long &value) const; 275 template bool CXmlElement::getAttribute(const std::string &name, long long &value) const; 276 template bool CXmlElement::getAttribute(const std::string &name, unsigned long long &value) const; 277 template bool CXmlElement::getAttribute(const std::string &name, float &value) const; 278 template bool CXmlElement::getAttribute(const std::string &name, double &value) const; 279 280 template void CXmlElement::setAttribute(const std::string &name, const std::string &value); 281 template void CXmlElement::setAttribute(const std::string &name, const bool &value); 282 template void CXmlElement::setAttribute(const std::string &name, const short &value); 283 template void CXmlElement::setAttribute(const std::string &name, const unsigned short &value); 284 template void CXmlElement::setAttribute(const std::string &name, const int &value); 285 template void CXmlElement::setAttribute(const std::string &name, const unsigned int &value); 286 template void CXmlElement::setAttribute(const std::string &name, const long &value); 287 template void CXmlElement::setAttribute(const std::string &name, const unsigned long &value); 288 template void CXmlElement::setAttribute(const std::string &name, const long long &value); 289 template void CXmlElement::setAttribute(const std::string &name, const unsigned long long &value); 290 template void CXmlElement::setAttribute(const std::string &name, const float &value); 291 template void CXmlElement::setAttribute(const std::string &name, const double &value); 292