GCC Code Coverage Report


Directory: ./
File: include/hpp/util/parser.hh
Date: 2025-05-17 13:07:10
Exec Total Coverage
Lines: 0 1 0.0%
Functions: 0 1 0.0%
Branches: 0 0 -%

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 <functional>
35 #include <iostream>
36 #include <list>
37 #include <map>
38 #include <string>
39
40 namespace hpp {
41 namespace util {
42 namespace parser {
43 typedef tinyxml2::XMLElement XMLElement;
44 typedef tinyxml2::XMLDocument XMLDocument;
45 typedef tinyxml2::XMLDeclaration XMLDeclaration;
46 typedef tinyxml2::XMLAttribute XMLAttribute;
47 typedef tinyxml2::XMLNode XMLNode;
48 typedef tinyxml2::XMLText XMLText;
49 typedef tinyxml2::XMLComment XMLComment;
50
51 typedef tinyxml2::XMLPrinter XMLPrinter;
52
53 class RootFactory;
54
55 /// \defgroup factories
56 ///
57 /// \brief Classes used to build object from XML documents.
58 ///
59 /// See section \ref hpp_manipulation_urdf_extend_sec for more information
60 /// about how to extend the parser with factories.
61
62 /// \addtogroup factories
63 /// \{
64
65 /// \brief Class that catch XML Parser events for a specific tag and build the
66 /// corresponding Object.
67 ///
68 /// Derive this class if you wish to extend the Parser.
69 /// The event callbacks are called in the following order:
70 /// \li ObjectFactory::init after having created the object.
71 /// \li ObjectFactory::setAttribute for each attribute of the tag.
72 /// \li ObjectFactory::finishAttributes after having processed every attribute.
73 /// \li ObjectFactory::addTextChild when a child is a text element.
74 /// \li ObjectFactory::finishTags when all the children have been parsed.
75 /// \li ObjectFactory::finishFile when the file has been fully parsed.
76 ///
77 /// \note The derived class must have the following construtor
78 /// \code
79 /// DerivedFactory (ObjectFactory* parent, const XMLElement* element) :
80 /// ObjectFactory (parent, element)
81 /// {
82 /// /*
83 /// * Keep in mind that it might be more convenient
84 /// * to build objects in an event callback, when some information
85 /// * has already been parsed.
86 /// */
87 /// }
88 /// \endcode
89 class ObjectFactory {
90 public:
91 typedef std::list<ObjectFactory*> ObjectFactoryList;
92
93 ObjectFactory(ObjectFactory* parent = NULL, const XMLElement* element = NULL);
94
95 virtual ~ObjectFactory() {}
96 /// \name Events
97 /// \{
98
99 /// Called when the object is created.
100 /// \return True to continue parsing this tag, False otherwise.
101 virtual bool init();
102
103 /// Called for each attribute.
104 /// A few reserved name are automatocally catched. The reserved names are
105 /// "name" and "id".
106 /// "name" expects a string.
107 /// "id" expects an unsigned integer and can be use to define pointers to
108 /// elements.
109 void setAttribute(const XMLAttribute* attr);
110
111 /// Add Text child.
112 virtual void addTextChild(const XMLText* text);
113
114 /// Called when all the attributes have been processed.
115 /// \return True to continue parsing this tag, False otherwise.
116 virtual bool finishAttributes();
117
118 /// Called when all the child tags have been processed.
119 virtual void finishTags();
120
121 /// Called when parsing is finished.
122 virtual void finishFile();
123
124 /// \}
125
126 /// \name Write to file
127 /// \{
128
129 /// Constructor for writing objects from scratch
130 ObjectFactory(const std::string& tagName, ObjectFactory* parent = NULL);
131
132 /// Add an attribute
133 void addAttribute(const std::string& name, const std::string& value);
134
135 /// Add this factory as child of the node argument.
136 /// Tags are handled throught children so you should add children
137 /// before calling this function.
138 /// If you factory must write something different from tags (XMLText
139 /// or XMLComment), reimplement method impl_write.
140 XMLNode* write(XMLNode* node) const;
141
142 /// \}
143
144 /// \name Accessors
145 /// \{
146
147 /// Return tag name of the element is any.
148 /// Returns "No element" otherwise.
149 std::string tagName() const;
150
151 /// Return the content of the attribute name, or an
152 /// empty string.
153 std::string name() const;
154
155 /// Check if an attribute was set.
156 bool hasAttribute(const std::string& attr) const;
157
158 /// Return a given attributes.
159 std::string getAttribute(const std::string& attr) const;
160
161 /// Get a list of ObjectFactory whose tag name is type.
162 ObjectFactoryList getChildrenOfType(std::string type);
163
164 /// Get the ObjectFactory whose tag name is type.
165 /// \param[out] o Set to the first element of the requested type.
166 /// \return true if there was only element of the requested type. false if
167 /// there are more than one. \throws std::invalid_argument if no ObjectFactory
168 /// of the requested type exists.
169 bool getChildOfType(std::string type, ObjectFactory*& o);
170
171 /// \}
172
173 /// Set the name.
174 /// The default value is the value of the attribute "name"
175 /// of the XML tag or an empty string if this does not exist.
176 void name(const std::string& n);
177
178 /// See name(const std::string&)
179 void name(const char* n);
180
181 /// Cast this class to any child class.
182 template <typename T>
183 T* as() {
184 return static_cast<T*>(this);
185 }
186
187 protected:
188 ObjectFactory(ObjectFactory* root);
189
190 ObjectFactory* parent();
191
192 virtual ObjectFactory* root();
193
194 bool hasParent() const;
195
196 const XMLElement* XMLelement();
197
198 virtual void impl_setAttribute(const XMLAttribute* attr);
199
200 virtual void impl_write(XMLElement* element) const;
201
202 void addChild(ObjectFactory* child);
203
204 virtual std::ostream& print(std::ostream& os) const;
205
206 private:
207 ObjectFactory* parent_;
208 ObjectFactory* root_;
209 typedef std::map<std::string, ObjectFactoryList> ChildrenMap;
210 ChildrenMap children_;
211
212 const XMLElement* element_;
213
214 typedef std::map<std::string, std::string> AttributeMap;
215 AttributeMap attrMap_;
216 std::string name_, tagName_;
217 int id_;
218
219 friend std::ostream& operator<<(std::ostream&, const ObjectFactory&);
220 };
221 /// \}
222
223 /// To add a ObjectFactory to the Parser, use:
224 /// Parser::addObjectFactory (TagName, create <ObjectFactory>)
225 template <typename T>
226 ObjectFactory* create(ObjectFactory* parent = NULL,
227 const XMLElement* element = NULL) {
228 return new T(parent, element);
229 }
230
231 /// \brief Parse an XML document
232 ///
233 /// This class uses the tinyXML library and derived classes of ObjectFactory
234 /// to build object from an XML document.
235 /// To extend its capabilities, see ObjectFactory.
236 class Parser {
237 public:
238 typedef std::function<ObjectFactory*(ObjectFactory*, const XMLElement*)>
239 FactoryType;
240
241 /// Constructor
242 /// \param defaultFactory The factory used when a tag is not known.
243 Parser(FactoryType defaultFactory = create<ObjectFactory>);
244
245 virtual ~Parser();
246
247 void addObjectFactory(const std::string& tagname, FactoryType factory);
248
249 virtual void parse(const char* xmlString);
250
251 virtual void parseFile(const std::string& filename);
252
253 ObjectFactory* root() const;
254
255 private:
256 XMLDocument doc_;
257 ObjectFactory* root_;
258
259 bool checkError() const;
260
261 void loadString(const char* xmlstring);
262
263 void parse();
264
265 void parseElement(const XMLElement* element, ObjectFactory* parent);
266
267 typedef std::map<std::string, FactoryType> ObjectFactoryMap;
268 typedef std::pair<std::string, FactoryType> ObjectFactoryPair;
269 typedef std::pair<ObjectFactoryMap::iterator, bool> ObjectFactoryInsertRet;
270 ObjectFactoryMap objFactoryMap_;
271 FactoryType defaultFactory_;
272
273 typedef std::list<ObjectFactory*> ObjectFactoryList;
274 ObjectFactoryList objectFactories_;
275
276 std::ostream& print(std::ostream&) const;
277 friend std::ostream& operator<<(std::ostream&, const Parser&);
278 };
279
280 std::ostream& operator<<(std::ostream&, const ObjectFactory&);
281 std::ostream& operator<<(std::ostream&, const Parser&);
282 } // namespace parser
283 } // namespace util
284 } // namespace hpp
285
286 #endif // HPP_MANIPULATION_PARSER_HH
287