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 <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