GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: include/hpp/manipulation/parser/parser.hh Lines: 12 18 66.7 %
Date: 2024-05-05 11:05:40 Branches: 5 22 22.7 %

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
#ifndef HPP_MANIPULATION_PARSER_HH
30
#define HPP_MANIPULATION_PARSER_HH
31
32
#include <tinyxml2.h>
33
34
#include <hpp/manipulation/fwd.hh>
35
#include <iostream>
36
#include <list>
37
#include <map>
38
#include <string>
39
40
namespace hpp {
41
namespace manipulation {
42
namespace parser {
43
typedef tinyxml2::XMLElement XMLElement;
44
typedef tinyxml2::XMLDocument XMLDocument;
45
typedef tinyxml2::XMLAttribute XMLAttribute;
46
typedef tinyxml2::XMLNode XMLNode;
47
typedef tinyxml2::XMLText XMLText;
48
49
class RootFactory;
50
51
/// \defgroup factories
52
///
53
/// \brief    Classes used to build object from XML documents.
54
///
55
/// See section \ref hpp_manipulation_urdf_extend_sec for more information
56
/// about how to extend the parser with factories.
57
58
/// \addtogroup factories
59
/// \{
60
61
/// \brief Class that catch XML Parser events for a specific tag and build the
62
/// corresponding Object.
63
///
64
/// Derive this class if you wish to extend the Parser.
65
/// The event callbacks are called in the following order:
66
/// \li ObjectFactory::init after having created the object.
67
/// \li ObjectFactory::setAttribute for each attribute of the tag.
68
/// \li ObjectFactory::finishAttributes after having processed every attribute.
69
/// \li ObjectFactory::addTextChild when a child is a text element.
70
/// \li ObjectFactory::finishTags when all the children have been parsed.
71
/// \li ObjectFactory::finishFile when the file has been fully parsed.
72
///
73
/// \note The derived class must have the following construtor
74
/// \code
75
/// DerivedFactory (ObjectFactory* parent, const XMLElement* element) :
76
///       ObjectFactory (parent, element)
77
/// {
78
///   /*
79
///    * Keep in mind that it might be more convenient
80
///    * to build objects in an event callback, when some information
81
///    * has already been parsed.
82
///    */
83
/// }
84
/// \endcode
85
class ObjectFactory {
86
 public:
87
  typedef std::vector<ObjectFactory*> ObjectFactoryList;
88
89
  ObjectFactory(ObjectFactory* parent = NULL, const XMLElement* element = NULL);
90
91
64
  virtual ~ObjectFactory() {}
92
93
  /// \name Events
94
  /// \{
95
96
  /// Called when the object is created.
97
  /// \return True to continue parsing this tag, False otherwise.
98
  virtual bool init();
99
100
  /// Called for each attribute.
101
  /// A few reserved name are automatocally catched. The reserved names are
102
  /// "name" and "id".
103
  /// "name" expects a string.
104
  /// "id" expects an unsigned integer and can be use to define pointers to
105
  /// elements.
106
  void setAttribute(const XMLAttribute* attr);
107
108
  /// Add Text child.
109
  virtual void addTextChild(const XMLText* text);
110
111
  /// Called when all the attributes have been processed.
112
  /// \return True to continue parsing this tag, False otherwise.
113
  virtual bool finishAttributes();
114
115
  /// Called when all the child tags have been processed.
116
  virtual void finishTags();
117
118
  /// Called when parsing is finished.
119
  virtual void finishFile();
120
121
  /// \}
122
123
  /// \name Accessors
124
  /// \{
125
126
  /// Return tag name of the element is any.
127
  /// Returns "No element" otherwise.
128
  std::string tagName() const;
129
130
  /// Return the content of the attribute name, or an
131
  /// empty string.
132
  std::string name() const;
133
134
  /// Check if an attribute was set.
135
  bool hasAttribute(const std::string& attr) const;
136
137
  /// Return a given attributes.
138
  std::string getAttribute(const std::string& attr) const;
139
140
  /// Get a list of ObjectFactory whose tag name is type.
141
  ObjectFactoryList getChildrenOfType(std::string type);
142
143
  /// Get the ObjectFactory whose tag name is type.
144
  /// \param[out] o Set to the first element of the requested type.
145
  /// \return true if there was only element of the requested type. false if
146
  /// there are more than one. \throws std::invalid_argument if no ObjectFactory
147
  /// of the requested type exists.
148
  bool getChildOfType(std::string type, ObjectFactory*& o);
149
150
  /// \}
151
152
  /// Set the name.
153
  /// The default value is the value of the attribute "name"
154
  /// of the XML tag or an empty string if this does not exist.
155
  void name(const std::string& n);
156
157
  /// See name(const std::string&)
158
  void name(const char* n);
159
160
  /// Cast this class to any child class.
161
  template <typename T>
162
26
  T* as() {
163

26
    if (!dynamic_cast<T*>(this)) {
164
      std::ostringstream oss;
165
      oss << "Unexpected tag: " << this->tagName();
166
      throw std::invalid_argument(oss.str().c_str());
167
    }
168
26
    return static_cast<T*>(this);
169
  }
170
171
 protected:
172
  ObjectFactory(RootFactory* root);
173
174
  ObjectFactory* parent();
175
176
  RootFactory* root();
177
178
  bool hasParent() const;
179
180
  const XMLElement* XMLelement();
181
182
  virtual void impl_setAttribute(const XMLAttribute* attr);
183
184
  void addChild(ObjectFactory* child);
185
186
  virtual std::ostream& print(std::ostream& os) const;
187
188
 private:
189
  ObjectFactory* parent_;
190
  RootFactory* root_;
191
  typedef std::map<std::string, ObjectFactoryList> ChildrenMap;
192
  ChildrenMap children_;
193
194
  const XMLElement* element_;
195
196
  typedef std::map<std::string, std::string> AttributeMap;
197
  AttributeMap attrMap_;
198
  std::string name_;
199
  int id_;
200
201
  friend std::ostream& operator<<(std::ostream&, const ObjectFactory&);
202
};
203
204
/// Represent a XML document.
205
class RootFactory : public ObjectFactory {
206
 public:
207
28
  virtual ~RootFactory() {}
208
  RootFactory(const DevicePtr_t dev = DevicePtr_t());
209
210
  DevicePtr_t device() const;
211
212
2
  inline std::string prependPrefix(const std::string& in) const {
213
2
    if (prefix_.empty()) return in;
214
    return prefix_ + in;
215
  }
216
217
  inline std::string removePrefix(const std::string& in) const {
218
    if (prefix_.empty()) return in;
219
    assert(in.compare(0, prefix_.size(), prefix_) == 0);
220
    return in.substr(prefix_.size());
221
  }
222
223
7
  void prefix(const std::string& prefix) {
224
7
    if (prefix.empty()) return;
225
    prefix_ = prefix + "/";
226
  }
227
228
 private:
229
  DevicePtr_t device_;
230
  std::string prefix_;
231
};
232
233
/// \}
234
235
/// To add a ObjectFactory to the Parser, use:
236
/// Parser::addObjectFactory (TagName, create <ObjectFactory>)
237
template <typename T>
238
30
ObjectFactory* create(ObjectFactory* parent = NULL,
239
                      const XMLElement* element = NULL) {
240
30
  return new T(parent, element);
241
}
242
243
/// \brief Parse an XML document
244
///
245
/// This class uses the tinyXML library and derived classes of ObjectFactory
246
/// to build object from an XML document.
247
/// To extend its capabilities, see ObjectFactory.
248
class Parser {
249
 public:
250
  typedef ObjectFactory* (*FactoryType)(ObjectFactory*, const XMLElement*);
251
  typedef ObjectFactory::ObjectFactoryList ObjectFactoryList;
252
253
  /// Constructor
254
  /// \param fillWithDefaultFactories Set to true if you want to insert the
255
  /// default
256
  ///        factories. If set to false, the created instance will have no
257
  ///        factories.
258
  /// \param defaultFactory The factory used when a tag is not know.
259
  Parser(bool fillWithDefaultFactories = true,
260
         FactoryType defaultFactory = create<ObjectFactory>);
261
262
  ~Parser();
263
264
  void addObjectFactory(const std::string& tagname, FactoryType factory);
265
266
  void parseString(const std::string& xmlString, DevicePtr_t robot);
267
268
  void parseFile(const std::string& filename, DevicePtr_t robot);
269
270
15
  const ObjectFactoryList& objectFactories() const { return objectFactories_; }
271
272
  /// Set the prefix of all joints
273
  void prefix(const std::string& prefix) { prefix_ = prefix; }
274
275
 private:
276
  XMLDocument doc_;
277
  RootFactory* root_;
278
  DevicePtr_t device_;
279
280
  void loadFile(const char* filename);
281
282
  void loadString(const char* xmlstring);
283
284
  void parse();
285
286
  void parseElement(const XMLElement* element, ObjectFactory* parent);
287
288
  typedef std::map<std::string, FactoryType> ObjectFactoryMap;
289
  typedef std::pair<std::string, FactoryType> ObjectFactoryPair;
290
  typedef std::pair<ObjectFactoryMap::iterator, bool> ObjectFactoryInsertRet;
291
  ObjectFactoryMap objFactoryMap_;
292
  FactoryType defaultFactory_;
293
294
  ObjectFactoryList objectFactories_;
295
296
  std::string prefix_;
297
298
  std::ostream& print(std::ostream&) const;
299
  friend std::ostream& operator<<(std::ostream&, const Parser&);
300
};
301
302
std::ostream& operator<<(std::ostream&, const ObjectFactory&);
303
std::ostream& operator<<(std::ostream&, const Parser&);
304
}  // namespace parser
305
}  // namespace manipulation
306
}  // namespace hpp
307
308
#endif  //  HPP_MANIPULATION_PARSER_HH