| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright (c) 2014, LAAS-CNRS | ||
| 2 | // Authors: Joseph Mirabel (joseph.mirabel@laas.fr) | ||
| 3 | // | ||
| 4 | |||
| 5 | // Redistribution and use in source and binary forms, with or without | ||
| 6 | // modification, are permitted provided that the following conditions are | ||
| 7 | // met: | ||
| 8 | // | ||
| 9 | // 1. Redistributions of source code must retain the above copyright | ||
| 10 | // notice, this list of conditions and the following disclaimer. | ||
| 11 | // | ||
| 12 | // 2. Redistributions in binary form must reproduce the above copyright | ||
| 13 | // notice, this list of conditions and the following disclaimer in the | ||
| 14 | // documentation and/or other materials provided with the distribution. | ||
| 15 | // | ||
| 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| 19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| 20 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| 21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| 22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| 23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | ||
| 27 | // DAMAGE. | ||
| 28 | |||
| 29 | #include "hpp/util/parser.hh" | ||
| 30 | |||
| 31 | #include <stdexcept> | ||
| 32 | |||
| 33 | #include "hpp/util/debug.hh" | ||
| 34 | |||
| 35 | namespace hpp { | ||
| 36 | namespace util { | ||
| 37 | namespace parser { | ||
| 38 | ✗ | Parser::Parser(FactoryType defaultFactory) | |
| 39 | ✗ | : doc_(), root_(NULL), defaultFactory_(defaultFactory) {} | |
| 40 | |||
| 41 | ✗ | Parser::~Parser() { | |
| 42 | ✗ | for (ObjectFactoryList::iterator it = objectFactories_.begin(); | |
| 43 | ✗ | it != objectFactories_.end(); ++it) | |
| 44 | ✗ | delete *it; | |
| 45 | ✗ | if (root_ != NULL) delete root_; | |
| 46 | ✗ | } | |
| 47 | |||
| 48 | ✗ | void Parser::parse(const char* xmlString) { | |
| 49 | ✗ | doc_.Parse(xmlString); | |
| 50 | |||
| 51 | ✗ | parse(); | |
| 52 | ✗ | } | |
| 53 | |||
| 54 | ✗ | void Parser::parseFile(const std::string& filename) { | |
| 55 | ✗ | doc_.LoadFile(filename.c_str()); | |
| 56 | ✗ | parse(); | |
| 57 | ✗ | } | |
| 58 | |||
| 59 | ✗ | bool Parser::checkError() const { | |
| 60 | ✗ | if (doc_.Error()) { | |
| 61 | hppDout(error, doc_.ErrorStr()); | ||
| 62 | ✗ | return true; | |
| 63 | } | ||
| 64 | ✗ | return false; | |
| 65 | } | ||
| 66 | |||
| 67 | ✗ | void Parser::parse() { | |
| 68 | ✗ | const XMLElement* el = doc_.RootElement(); | |
| 69 | ✗ | root_ = new ObjectFactory(); | |
| 70 | ✗ | while (el != NULL) { | |
| 71 | ✗ | parseElement(el, root_); | |
| 72 | ✗ | el = el->NextSiblingElement(); | |
| 73 | } | ||
| 74 | ✗ | for (ObjectFactoryList::iterator it = objectFactories_.begin(); | |
| 75 | ✗ | it != objectFactories_.end(); ++it) | |
| 76 | ✗ | (*it)->finishFile(); | |
| 77 | ✗ | } | |
| 78 | |||
| 79 | ✗ | void Parser::addObjectFactory(const std::string& tagname, FactoryType factory) { | |
| 80 | ObjectFactoryInsertRet ret = | ||
| 81 | ✗ | objFactoryMap_.insert(ObjectFactoryPair(tagname, factory)); | |
| 82 | ✗ | if (!ret.second) throw std::logic_error("This tagname already exist"); | |
| 83 | ✗ | } | |
| 84 | |||
| 85 | ✗ | void Parser::parseElement(const XMLElement* element, ObjectFactory* parent) { | |
| 86 | ✗ | if (element == NULL) return; | |
| 87 | |||
| 88 | ✗ | ObjectFactory* o = NULL; | |
| 89 | /// Look for this element in the map | ||
| 90 | ✗ | ObjectFactoryMap::const_iterator it = objFactoryMap_.find(element->Value()); | |
| 91 | ✗ | if (it != objFactoryMap_.end()) | |
| 92 | ✗ | o = it->second(parent, element); | |
| 93 | else { | ||
| 94 | ✗ | o = defaultFactory_(parent, element); | |
| 95 | hppDout(warning, "I have no factory for tag " << o->tagName()); | ||
| 96 | } | ||
| 97 | ✗ | objectFactories_.push_back(o); | |
| 98 | ✗ | if (!o->init()) return; | |
| 99 | ✗ | for (const XMLAttribute* attr = element->FirstAttribute(); attr; | |
| 100 | ✗ | attr = attr->Next()) | |
| 101 | ✗ | o->setAttribute(attr); | |
| 102 | ✗ | if (!o->finishAttributes()) return; | |
| 103 | |||
| 104 | /// Loop over is child tags | ||
| 105 | ✗ | for (const XMLNode* el = element->FirstChild(); el; el = el->NextSibling()) { | |
| 106 | ✗ | if (el->ToElement() != NULL) { | |
| 107 | ✗ | parseElement(el->ToElement(), o); | |
| 108 | ✗ | } else if (el->ToUnknown() != NULL) { | |
| 109 | hppDout(warning, "Unknown Node in XML file: " << el->Value()); | ||
| 110 | ✗ | } else if (el->ToText() != NULL) { | |
| 111 | ✗ | o->addTextChild(el->ToText()); | |
| 112 | ✗ | } else if (el->ToComment() != NULL) { | |
| 113 | } | ||
| 114 | } | ||
| 115 | ✗ | o->finishTags(); | |
| 116 | } | ||
| 117 | |||
| 118 | ✗ | ObjectFactory* Parser::root() const { return root_; } | |
| 119 | |||
| 120 | ✗ | std::ostream& Parser::print(std::ostream& os) const { | |
| 121 | ✗ | os << "Parser with " << objectFactories_.size() << " object." << std::endl; | |
| 122 | ✗ | if (root_ != NULL) os << *root_; | |
| 123 | ✗ | return os; | |
| 124 | } | ||
| 125 | |||
| 126 | ✗ | std::ostream& operator<<(std::ostream& os, const Parser& p) { | |
| 127 | ✗ | return p.print(os); | |
| 128 | } | ||
| 129 | |||
| 130 | ✗ | std::ostream& operator<<(std::ostream& os, const ObjectFactory& o) { | |
| 131 | ✗ | return o.print(os); | |
| 132 | } | ||
| 133 | |||
| 134 | ✗ | ObjectFactory::ObjectFactory(ObjectFactory* parent, const XMLElement* element) | |
| 135 | ✗ | : parent_(parent), root_(NULL), element_(element), id_(-1) { | |
| 136 | ✗ | if (element_ != NULL) | |
| 137 | ✗ | tagName_ = element_->Value(); | |
| 138 | else | ||
| 139 | ✗ | tagName_ = "unamed_tag"; | |
| 140 | ✗ | if (parent_ == NULL) { | |
| 141 | ✗ | root_ = this; | |
| 142 | } else { | ||
| 143 | ✗ | root_ = parent_->root(); | |
| 144 | ✗ | if (element_ != NULL) parent_->addChild(this); | |
| 145 | } | ||
| 146 | ✗ | } | |
| 147 | |||
| 148 | ✗ | ObjectFactory::ObjectFactory(ObjectFactory* root) | |
| 149 | ✗ | : parent_(NULL), root_(root), element_(NULL), id_(-1) {} | |
| 150 | |||
| 151 | ✗ | bool ObjectFactory::init() { return true; } | |
| 152 | |||
| 153 | ✗ | bool ObjectFactory::finishAttributes() { return true; } | |
| 154 | |||
| 155 | ✗ | void ObjectFactory::finishTags() {} | |
| 156 | |||
| 157 | ✗ | void ObjectFactory::finishFile() {} | |
| 158 | |||
| 159 | ✗ | void ObjectFactory::addTextChild(const XMLText* /* text */) {} | |
| 160 | |||
| 161 | ✗ | ObjectFactory::ObjectFactory(const std::string& tagName, ObjectFactory* parent) | |
| 162 | ✗ | : parent_(parent), root_(NULL), element_(NULL), tagName_(tagName), id_(-1) { | |
| 163 | ✗ | if (parent_ == NULL) | |
| 164 | ✗ | root_ = this; | |
| 165 | else { | ||
| 166 | ✗ | root_ = parent_->root(); | |
| 167 | ✗ | parent_->addChild(this); | |
| 168 | } | ||
| 169 | ✗ | } | |
| 170 | |||
| 171 | ✗ | void ObjectFactory::addAttribute(const std::string& name, | |
| 172 | const std::string& value) { | ||
| 173 | ✗ | attrMap_[name] = value; | |
| 174 | ✗ | } | |
| 175 | |||
| 176 | /// Get a new XMLElement from the content of this factory | ||
| 177 | ✗ | XMLNode* ObjectFactory::write(XMLNode* parent) const { | |
| 178 | ✗ | XMLElement* el = parent->GetDocument()->NewElement(tagName().c_str()); | |
| 179 | ✗ | for (AttributeMap::const_iterator it = attrMap_.begin(); it != attrMap_.end(); | |
| 180 | ✗ | ++it) | |
| 181 | ✗ | el->SetAttribute(it->first.c_str(), it->second.c_str()); | |
| 182 | ✗ | for (ChildrenMap::const_iterator it = children_.begin(); | |
| 183 | ✗ | it != children_.end(); ++it) | |
| 184 | ✗ | for (ObjectFactoryList::const_iterator of = it->second.begin(); | |
| 185 | ✗ | of != it->second.end(); ++of) | |
| 186 | ✗ | (*of)->write(el); | |
| 187 | ✗ | impl_write(el); | |
| 188 | ✗ | return parent->InsertEndChild(el); | |
| 189 | } | ||
| 190 | |||
| 191 | ✗ | std::string ObjectFactory::tagName() const { return tagName_; } | |
| 192 | |||
| 193 | ✗ | std::string ObjectFactory::name() const { return name_; } | |
| 194 | |||
| 195 | ✗ | void ObjectFactory::name(const std::string& n) { name_ = n; } | |
| 196 | |||
| 197 | ✗ | void ObjectFactory::name(const char* n) { name(std::string(n)); } | |
| 198 | |||
| 199 | ✗ | ObjectFactory* ObjectFactory::parent() { return parent_; } | |
| 200 | |||
| 201 | ✗ | ObjectFactory* ObjectFactory::root() { return root_; } | |
| 202 | |||
| 203 | ✗ | bool ObjectFactory::hasParent() const { return parent_ != NULL; } | |
| 204 | |||
| 205 | ✗ | const XMLElement* ObjectFactory::XMLelement() { return element_; } | |
| 206 | |||
| 207 | ✗ | void ObjectFactory::impl_setAttribute(const XMLAttribute* /* attr */) {} | |
| 208 | |||
| 209 | ✗ | void ObjectFactory::impl_write(XMLElement*) const {} | |
| 210 | |||
| 211 | ✗ | void ObjectFactory::addChild(ObjectFactory* child) { | |
| 212 | ✗ | children_[child->tagName()].push_back(child); | |
| 213 | ✗ | } | |
| 214 | |||
| 215 | ✗ | std::list<ObjectFactory*> ObjectFactory::getChildrenOfType(std::string type) { | |
| 216 | ✗ | return children_[type]; | |
| 217 | } | ||
| 218 | |||
| 219 | ✗ | bool ObjectFactory::getChildOfType(std::string type, ObjectFactory*& o) { | |
| 220 | ✗ | ObjectFactoryList l = getChildrenOfType(type); | |
| 221 | ✗ | if (l.empty()) { | |
| 222 | ✗ | throw std::invalid_argument("Tag " + tagName() + " has no child of type " + | |
| 223 | ✗ | type); | |
| 224 | } | ||
| 225 | ✗ | o = l.front(); | |
| 226 | ✗ | if (l.size() != 1) { | |
| 227 | hppDout(warning, "Tag " << tagName() << " has several children of type " | ||
| 228 | << type << ". All but the first will be ignored."); | ||
| 229 | ✗ | return false; | |
| 230 | } | ||
| 231 | ✗ | return true; | |
| 232 | ✗ | } | |
| 233 | |||
| 234 | ✗ | std::ostream& ObjectFactory::print(std::ostream& os) const { | |
| 235 | ✗ | os << "ObjectFactory " << tagName() << " with name " << name() << std::endl; | |
| 236 | ✗ | for (ChildrenMap::const_iterator itTagName = children_.begin(); | |
| 237 | ✗ | itTagName != children_.end(); ++itTagName) | |
| 238 | ✗ | for (ObjectFactoryList::const_iterator itObj = itTagName->second.begin(); | |
| 239 | ✗ | itObj != itTagName->second.end(); ++itObj) | |
| 240 | ✗ | os << **itObj; | |
| 241 | ✗ | return os; | |
| 242 | } | ||
| 243 | |||
| 244 | ✗ | void ObjectFactory::setAttribute(const XMLAttribute* attr) { | |
| 245 | ✗ | std::string n = std::string(attr->Name()); | |
| 246 | ✗ | if (n == "name") | |
| 247 | ✗ | name(attr->Value()); | |
| 248 | ✗ | else if (n == "id") { | |
| 249 | int v; | ||
| 250 | ✗ | if (attr->QueryIntValue(&v) != tinyxml2::XML_SUCCESS) { | |
| 251 | hppDout(error, "Attribute ID " << attr->Value() << " is incorrect."); | ||
| 252 | } else { | ||
| 253 | ✗ | id_ = (int)v; | |
| 254 | } | ||
| 255 | } | ||
| 256 | ✗ | attrMap_[n] = attr->Value(); | |
| 257 | ✗ | impl_setAttribute(attr); | |
| 258 | ✗ | } | |
| 259 | |||
| 260 | ✗ | bool ObjectFactory::hasAttribute(const std::string& attr) const { | |
| 261 | ✗ | return attrMap_.find(attr) != attrMap_.end(); | |
| 262 | } | ||
| 263 | |||
| 264 | ✗ | std::string ObjectFactory::getAttribute(const std::string& attr) const { | |
| 265 | ✗ | AttributeMap::const_iterator it = attrMap_.find(attr); | |
| 266 | ✗ | if (it == attrMap_.end()) { | |
| 267 | hppDout(error, "Asking for attribute " << attr); | ||
| 268 | ✗ | return std::string(); | |
| 269 | } | ||
| 270 | ✗ | return it->second; | |
| 271 | } | ||
| 272 | } // namespace parser | ||
| 273 | } // namespace util | ||
| 274 | } // namespace hpp | ||
| 275 |