Home | History | Annotate | Download | only in xmlserializer
      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