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