RapidXmlReader.h
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5  *
6  * ArmarX is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * ArmarX is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * @package
19  * @author
20  * @date
21  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22  * GNU General Public License
23  */
24 
25 #pragma once
26 
34 #include <experimental/source_location>
35 
36 #include <memory>
37 #include <string>
38 #include <fstream>
39 #include <streambuf>
40 #include <functional>
41 
42 
44 {
45  class RapidXmlReaderException : public armarx::LocalException
46  {
47  public:
48  RapidXmlReaderException(const std::string& message) noexcept :
49  armarx::LocalException(message)
50  { }
51 
52  ~RapidXmlReaderException() noexcept override
53  { }
54 
55  std::string name() const override
56  {
57  return "armarx::exceptions::local::RapidXmlWrapperException";
58  }
59  };
60 }
61 
62 
63 namespace armarx
64 {
65  class RapidXmlReader;
66  using RapidXmlReaderPtr = std::shared_ptr<RapidXmlReader>;
67 
69  {
70  friend class RapidXmlReader;
71 
72  private:
74  std::shared_ptr<rapidxml::xml_document<> > doc;
75  std::shared_ptr<char[]> cstr;
76  RapidXmlReaderNode(rapidxml::xml_node<>* node, std::shared_ptr<rapidxml::xml_document<> > doc, std::shared_ptr<char[]> cstr)
77  : node(node), doc(doc), cstr(cstr)
78  { }
79  void check(const std::string& msg = "",
80  const std::experimental::source_location& location = {}) const
81  {
83  if (!node)
84  {
85  std::stringstream str;
86  str << "RapidXmlWrapper NullPointerException\n"
87  << "from " << location.file_name() << ':' << location.line()
88  << " (" << location.function_name() << ")\nTrace:\n";
89 
91  str << "\nmsg: " << msg;
92  throw exceptions::local::RapidXmlReaderException(str.str());
93  }
94  }
95 
96  char* get_attrib_value(const char* attrName) const
97  {
99  check();
100  rapidxml::xml_attribute<>* attrib = node->first_attribute(attrName);
101 
102  if (!attrib)
103  {
104  throw exceptions::local::RapidXmlReaderException(std::string("Attribute '") + attrName + "' does not exist in node " + getPath());
105  }
106 
107  return attrib->value();
108  }
109 
110  public:
111  std::string toString() const
112  {
113  check();
114  std::stringstream str;
115  str << *node;
116  return str.str();
117  }
118 
120  {
121  return RapidXmlReaderNode(nullptr, std::shared_ptr<rapidxml::xml_document<> >(), std::shared_ptr<char[]>());
122  }
123 
124  /**
125  * @brief get_node_ptr only for legacy code.
126  * @return internal pointer
127  */
129  {
130  return node;
131  }
132 
134  {
135  ARMARX_TRACE;
136  check();
137  return RapidXmlReaderNode(node->parent(), doc, cstr);
138  }
139 
140  RapidXmlReaderNode first_node(const char* name = nullptr) const
141  {
142  ARMARX_TRACE;
143  check();
144  return RapidXmlReaderNode(node->first_node(name), doc, cstr);
145  }
146  RapidXmlReaderNode first_node_with_attr_value(const char* tagName, const char* attrName, const char* attrValue) const
147  {
148  ARMARX_TRACE;
149  for (RapidXmlReaderNode n = first_node(tagName); n.is_valid(); n = n.next_sibling(tagName))
150  {
151  if (n.has_attribute_with_value(attrName, attrValue))
152  {
153  return n;
154  }
155  }
156  return NullNode();
157  }
158  std::vector<RapidXmlReaderNode> nodes(const char* name = nullptr) const
159  {
160  ARMARX_TRACE;
161  std::vector<RapidXmlReaderNode> vec;
162  nodes(name, vec);
163  return vec;
164  }
165  void nodes(const char* name, std::vector<RapidXmlReaderNode>& vec) const
166  {
167  ARMARX_TRACE;
168  for (RapidXmlReaderNode n = first_node(name); n.is_valid(); n = n.next_sibling(name))
169  {
170  vec.push_back(n);
171  }
172  }
173  void nodes(const char* name1, const char* name2, std::vector<RapidXmlReaderNode>& vec) const
174  {
175  for (RapidXmlReaderNode n = first_node(name1); n.is_valid(); n = n.next_sibling(name1))
176  {
177  n.nodes(name2, vec);
178  }
179 
180  }
181  std::vector<RapidXmlReaderNode> nodes(const char* name1, const char* name2) const
182  {
183  std::vector<RapidXmlReaderNode> vec;
184  nodes(name1, name2, vec);
185  return vec;
186  }
187  std::vector<RapidXmlReaderNode> nodes(const char* name1, const char* name2, const char* name3) const
188  {
189  std::vector<RapidXmlReaderNode> vec;
190 
191  for (RapidXmlReaderNode n = first_node(name1); n.is_valid(); n = n.next_sibling(name1))
192  {
193  n.nodes(name2, name3, vec);
194  }
195 
196  return vec;
197  }
198  std::string attribute_value(const char* attrName) const
199  {
200  return std::string(get_attrib_value(attrName));
201  }
202 
203  bool has_node(const char* nodeName) const
204  {
205  check();
206  return node->first_node(nodeName) != nullptr;
207  }
208 
209  bool has_attribute(const char* attrName) const
210  {
211  check();
212  return node->first_attribute(attrName) != nullptr;
213  }
214  bool has_attribute_with_value(const char* attrName, const char* attrValue) const
215  {
216  check();
217  rapidxml::xml_attribute<>* attrib = node->first_attribute(attrName);
218  if (!attrib)
219  {
220  return false;
221  }
222  return std::string(attrib->value()) == std::string(attrValue);
223  }
224 
225  std::string attribute_value_or_default(const char* attrName, const std::string& defaultValue) const
226  {
227  check();
228  rapidxml::xml_attribute<>* attrib = node->first_attribute(attrName);
229 
230  if (!attrib)
231  {
232  return defaultValue;
233  }
234 
235  return std::string(attrib->value());
236  }
237 
238  bool attribute_as_bool(const char* attrName, const std::string& trueValue, const std::string& falseValue) const
239  {
240  std::string value = std::string(get_attrib_value(attrName));
241 
242  if (value == trueValue)
243  {
244  return true;
245  }
246  else if (value == falseValue)
247  {
248  return false;
249  }
250  else
251  {
252  throw exceptions::local::RapidXmlReaderException(std::string("Invalid value '") + value + "' for attribute '" + attrName + "'. Expecting '" + trueValue + "' or '" + falseValue + "'.");
253  }
254  }
255 
256  bool attribute_as_optional_bool(const char* name, const std::string& trueValue, const std::string& falseValue, bool defaultValue) const
257  {
258  check();
260 
261  if (!attrib)
262  {
263  return defaultValue;
264  }
265 
266  std::string value = std::string(attrib->value());
267 
268  if (value == trueValue)
269  {
270  return true;
271  }
272  else if (value == falseValue)
273  {
274  return false;
275  }
276  else
277  {
278  throw exceptions::local::RapidXmlReaderException(std::string("Invalid value '") + value + "' for attribute '" + name + "'. Expecting '" + trueValue + "' or '" + falseValue + "'.");
279  }
280  }
281 
282  float attribute_as_float(const char* attrName) const
283  {
284  return static_cast<float>(atof(get_attrib_value(attrName)));
285  }
286 
287  uint32_t attribute_as_uint(const char* attrName) const
288  {
289  std::stringstream strValue(get_attrib_value(attrName));
290  uint32_t retValue;
291  strValue >> retValue;
292  return retValue;
293  }
294 
295  std::vector<std::pair<std::string, std::string>> get_all_attributes() const
296  {
297  check();
298  std::vector<std::pair<std::string, std::string>> attributes;
299 
300  rapidxml::xml_attribute<>* attrib = node->first_attribute();
301 
302  while (attrib)
303  {
304  std::string name = std::string(attrib->name());
305  std::string value = std::string(attrib->value());
306  attributes.push_back({name, value});
307  attrib = attrib->next_attribute();
308  }
309 
310  return attributes;
311  }
312 
313  std::string value() const
314  {
315  check();
316  return std::string(node->value());
317  }
318 
319  float value_as_float() const
320  {
321  check();
322  return static_cast<float>(atof(node->value()));
323  }
324 
325  uint32_t value_as_uint32() const
326  {
327  check();
328  return static_cast<uint32_t>(armarx::toUInt(node->value()));
329  }
330 
331  uint16_t value_as_uint16() const
332  {
333  check();
334  return static_cast<uint16_t>(armarx::toUInt(node->value()));
335  }
336 
337  int32_t value_as_int32() const
338  {
339  check();
340  return static_cast<int32_t>(std::stoul(node->value(), nullptr, 0));
341  }
342 
343  int16_t value_as_int16() const
344  {
345  check();
346  return static_cast<int16_t>(std::stoul(node->value(), nullptr, 0));
347  }
348 
349  std::string name() const
350  {
351  check();
352  return std::string(node->name());
353  }
354 
356  {
357  check();
358  return node->type();
359  }
360 
361  std::string first_node_value(const char* nodeName = nullptr) const
362  {
363  check();
364  rapidxml::xml_node<>* childNode = node->first_node(nodeName);
365 
366  if (!childNode)
367  {
368  throw exceptions::local::RapidXmlReaderException(std::string("Node '") + nodeName + "' does not exist in node " + getPath());
369  }
370 
371  return std::string(childNode->value());
372  }
373 
374  std::string first_node_value_or_default(const char* name, const std::string& defaultValue) const
375  {
376  check();
377  rapidxml::xml_node<>* childNode = node->first_node(name);
378 
379  if (!childNode)
380  {
381  return defaultValue;
382  }
383 
384  return std::string(childNode->value());
385  }
386  RapidXmlReaderNode next_sibling(const char* name = nullptr) const
387  {
388  check();
389  return RapidXmlReaderNode(node->next_sibling(name), doc, cstr);
390  }
391 
392  bool is_valid() const
393  {
394  return node != nullptr;
395  }
396 
397  std::string getParentPath() const
398  {
399  check();
400  std::string result;
401  rapidxml::xml_node<>* p = node->parent();
402 
403  while (p)
404  {
405  result = std::string(p->name()) + "/" + result;
406  p = p->parent();
407  }
408 
409  return result;
410  }
411  std::string getPath() const
412  {
413  check();
414  return getParentPath() + name();
415  }
416  private:
417  static void collect_child_names(std::vector<std::string>& out, const RapidXmlReaderNode& n, const std::string& pre)
418  {
419  ARMARX_TRACE;
420  std::string name = pre + n.name();
421  const auto cs = n.nodes();
422 
423  if (cs.empty())
424  {
425  out.emplace_back(name);
426  return;
427  }
428  name += '/';
429  for (const auto& c : cs)
430  {
431  collect_child_names(out, c, name);
432  }
433  }
434  public:
435  std::vector<std::string> getChildPaths() const
436  {
437  ARMARX_TRACE;
438  std::vector<std::string> result;
439  if (is_valid())
440  {
441  collect_child_names(result, *this, getParentPath());
442  }
443  return result;
444  }
445  };
446 
448  {
449  private:
450  std::shared_ptr<rapidxml::xml_document<> > doc;
451  std::shared_ptr<char[]> cstr;
452 
453  RapidXmlReader(const std::string& xml)
454  : doc(new rapidxml::xml_document<>())
455  {
456  cstr.reset(new char[xml.size() + 1]); // Create char buffer to store string copy
457  strcpy(cstr.get(), xml.c_str()); // Copy string into char buffer
458  doc->parse<0>(cstr.get()); // Pass the non-const char* to parse()
459  }
460 
461  public:
462  static std::string ReadFileContents(const std::string& path)
463  {
464  bool found = false;
465  std::string absolutePath;
466  if (path.front() == '/') // Avoid <filesystem> in header ...
467  {
468  absolutePath = path;
469  found = true;
470  }
471  else
472  {
473  found = ArmarXDataPath::getAbsolutePath(path, absolutePath);
474  }
475 
476  std::ifstream t(absolutePath);
477  if (!found || !t.is_open())
478  {
479  throw exceptions::local::RapidXmlReaderException("Could not open file ") << path;
480  }
481 
482  std::string str;
483  t.seekg(0, std::ios::end);
484  str.reserve(t.tellg());
485  t.seekg(0, std::ios::beg);
486 
487  str.assign((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
488  return str;
489  }
490 
491  static RapidXmlReaderPtr FromXmlString(const std::string& xml)
492  {
493  RapidXmlReaderPtr wrapper(new RapidXmlReader(xml));
494  return wrapper;
495  }
496 
497  static RapidXmlReaderPtr FromFile(const std::string& path)
498  {
499  return FromXmlString(ReadFileContents(path));
500  }
501 
503  {
504  return RapidXmlReaderNode(doc.get(), doc, cstr);
505  }
506 
507  RapidXmlReaderNode getRoot(const char* name = nullptr)
508  {
509  return getDocument().first_node(name);
510  }
511 
512  };
513 
514 }
515 
516 
armarx::RapidXmlReaderPtr
std::shared_ptr< RapidXmlReader > RapidXmlReaderPtr
Definition: RapidXmlReader.h:66
armarx::RapidXmlReader::FromFile
static RapidXmlReaderPtr FromFile(const std::string &path)
Definition: RapidXmlReader.h:497
std::source_location
experimental::source_location source_location
Definition: Pointer.h:37
armarx::toUInt
unsigned int toUInt(const std::string &input)
Definition: StringHelpers.cpp:118
armarx::RapidXmlReaderNode::next_sibling
RapidXmlReaderNode next_sibling(const char *name=nullptr) const
Definition: RapidXmlReader.h:386
armarx::RapidXmlReaderNode::value_as_int16
int16_t value_as_int16() const
Definition: RapidXmlReader.h:343
str
std::string str(const T &t)
Definition: UserAssistedSegmenterGuiWidgetController.cpp:42
rapidxml::xml_node::next_sibling
xml_node< Ch > * next_sibling(const Ch *name=nullptr, std::size_t name_size=0, bool case_sensitive=true) const
Gets next sibling node, optionally matching node name.
Definition: rapidxml.hpp:1121
armarx::RapidXmlReader::ReadFileContents
static std::string ReadFileContents(const std::string &path)
Definition: RapidXmlReader.h:462
armarx::RapidXmlReaderNode::first_node_with_attr_value
RapidXmlReaderNode first_node_with_attr_value(const char *tagName, const char *attrName, const char *attrValue) const
Definition: RapidXmlReader.h:146
armarx::RapidXmlReader::FromXmlString
static RapidXmlReaderPtr FromXmlString(const std::string &xml)
Definition: RapidXmlReader.h:491
armarx::RapidXmlReaderNode::type
rapidxml::node_type type()
Definition: RapidXmlReader.h:355
rapidxml::xml_attribute::next_attribute
xml_attribute< Ch > * next_attribute(const Ch *name=nullptr, std::size_t name_size=0, bool case_sensitive=true) const
Gets next attribute, optionally matching attribute name.
Definition: rapidxml.hpp:935
armarx::RapidXmlReaderNode::attribute_as_optional_bool
bool attribute_as_optional_bool(const char *name, const std::string &trueValue, const std::string &falseValue, bool defaultValue) const
Definition: RapidXmlReader.h:256
armarx::exceptions::local::RapidXmlReaderException
Definition: RapidXmlReader.h:45
armarx::RapidXmlReaderNode::NullNode
static RapidXmlReaderNode NullNode()
Definition: RapidXmlReader.h:119
armarx::RapidXmlReaderNode::attribute_value
std::string attribute_value(const char *attrName) const
Definition: RapidXmlReader.h:198
trace.h
armarx::exceptions::local::RapidXmlReaderException::name
std::string name() const override
Definition: RapidXmlReader.h:55
armarx::RapidXmlReaderNode::getParentPath
std::string getParentPath() const
Definition: RapidXmlReader.h:397
c
constexpr T c
Definition: UnscentedKalmanFilterTest.cpp:43
message
message(STATUS "Boost-Library-Dir: " "${Boost_LIBRARY_DIRS}") message(STATUS "Boost-LIBRARIES
Definition: CMakeLists.txt:8
armarx::RapidXmlReader::getDocument
RapidXmlReaderNode getDocument()
Definition: RapidXmlReader.h:502
armarx::RapidXmlReaderNode::getChildPaths
std::vector< std::string > getChildPaths() const
Definition: RapidXmlReader.h:435
rapidxml::xml_node::first_attribute
xml_attribute< Ch > * first_attribute(const Ch *name=nullptr, std::size_t name_size=0, bool case_sensitive=true) const
Gets first attribute of node, optionally matching attribute name.
Definition: rapidxml.hpp:1151
armarx::RapidXmlReaderNode::nodes
std::vector< RapidXmlReaderNode > nodes(const char *name1, const char *name2) const
Definition: RapidXmlReader.h:181
armarx::RapidXmlReaderNode::get_all_attributes
std::vector< std::pair< std::string, std::string > > get_all_attributes() const
Definition: RapidXmlReader.h:295
StringHelpers.h
armarx::RapidXmlReaderNode::attribute_as_uint
uint32_t attribute_as_uint(const char *attrName) const
Definition: RapidXmlReader.h:287
rapidxml::xml_attribute
Class representing attribute node of XML document.
Definition: rapidxml.hpp:139
armarx::RapidXmlReaderNode::attribute_as_bool
bool attribute_as_bool(const char *attrName, const std::string &trueValue, const std::string &falseValue) const
Definition: RapidXmlReader.h:238
armarx::RapidXmlReaderNode::attribute_as_float
float attribute_as_float(const char *attrName) const
Definition: RapidXmlReader.h:282
armarx::RapidXmlReaderNode::has_node
bool has_node(const char *nodeName) const
Definition: RapidXmlReader.h:203
armarx::RapidXmlReaderNode::has_attribute
bool has_attribute(const char *attrName) const
Definition: RapidXmlReader.h:209
armarx::RapidXmlReaderNode::name
std::string name() const
Definition: RapidXmlReader.h:349
armarx::RapidXmlReaderNode::get_node_ptr
rapidxml::xml_node * get_node_ptr() const
get_node_ptr only for legacy code.
Definition: RapidXmlReader.h:128
ARMARX_TRACE
#define ARMARX_TRACE
Definition: trace.h:69
armarx::RapidXmlReaderNode::parent_node
RapidXmlReaderNode parent_node() const
Definition: RapidXmlReader.h:133
armarx::RapidXmlReaderNode::value_as_float
float value_as_float() const
Definition: RapidXmlReader.h:319
armarx::exceptions::local
Definition: DynamicLibraryException.h:31
armarx::RapidXmlReaderNode::value_as_uint16
uint16_t value_as_uint16() const
Definition: RapidXmlReader.h:331
armarx::exceptions::local::RapidXmlReaderException::RapidXmlReaderException
RapidXmlReaderException(const std::string &message) noexcept
Definition: RapidXmlReader.h:48
armarx::RapidXmlReaderNode::nodes
void nodes(const char *name, std::vector< RapidXmlReaderNode > &vec) const
Definition: RapidXmlReader.h:165
armarx::RapidXmlReaderNode::has_attribute_with_value
bool has_attribute_with_value(const char *attrName, const char *attrValue) const
Definition: RapidXmlReader.h:214
armarx::RapidXmlReader
Definition: RapidXmlReader.h:447
armarx::RapidXmlReaderNode
Definition: RapidXmlReader.h:68
armarx::control::hardware_config::tagName
std::string tagName(ConfigTag tag)
Definition: Config.cpp:302
armarx::RapidXmlReaderNode::nodes
void nodes(const char *name1, const char *name2, std::vector< RapidXmlReaderNode > &vec) const
Definition: RapidXmlReader.h:173
rapidxml::xml_node::first_node
xml_node< Ch > * first_node(const Ch *name=nullptr, std::size_t name_size=0, bool case_sensitive=true) const
Gets first child node, optionally matching node name.
Definition: rapidxml.hpp:1027
rapidxml::xml_document
This class represents root of the DOM hierarchy.
Definition: rapidxml.hpp:140
armarx::RapidXmlReaderNode::value
std::string value() const
Definition: RapidXmlReader.h:313
armarx::RapidXmlReaderNode::getPath
std::string getPath() const
Definition: RapidXmlReader.h:411
armarx::RapidXmlReaderNode::nodes
std::vector< RapidXmlReaderNode > nodes(const char *name1, const char *name2, const char *name3) const
Definition: RapidXmlReader.h:187
ExpressionException.h
armarx::RapidXmlReaderNode::toString
std::string toString() const
Definition: RapidXmlReader.h:111
rapidxml::xml_node
Class representing a node of XML document.
Definition: rapidxml.hpp:138
rapidxml::node_type
node_type
Enumeration listing all node types produced by the parser.
Definition: rapidxml.hpp:144
rapidxml::xml_node::type
node_type type() const
Gets type of node.
Definition: rapidxml.hpp:1000
armarx::RapidXmlReaderNode::value_as_int32
int32_t value_as_int32() const
Definition: RapidXmlReader.h:337
armarx::RapidXmlReaderNode::first_node_value_or_default
std::string first_node_value_or_default(const char *name, const std::string &defaultValue) const
Definition: RapidXmlReader.h:374
armarx::exceptions::local::RapidXmlReaderException::~RapidXmlReaderException
~RapidXmlReaderException() noexcept override
Definition: RapidXmlReader.h:52
armarx::RapidXmlReaderNode::nodes
std::vector< RapidXmlReaderNode > nodes(const char *name=nullptr) const
Definition: RapidXmlReader.h:158
armarx::RapidXmlReaderNode::value_as_uint32
uint32_t value_as_uint32() const
Definition: RapidXmlReader.h:325
armarx::RapidXmlReaderNode::is_valid
bool is_valid() const
Definition: RapidXmlReader.h:392
armarx::ArmarXDataPath::getAbsolutePath
static bool getAbsolutePath(const std::string &relativeFilename, std::string &storeAbsoluteFilename, const std::vector< std::string > &additionalSearchPaths={}, bool verbose=true)
Definition: ArmarXDataPath.cpp:111
rapidxml.hpp
ArmarXDataPath.h
armarx::RapidXmlReaderNode::first_node
RapidXmlReaderNode first_node(const char *name=nullptr) const
Definition: RapidXmlReader.h:140
armarx::RapidXmlReaderNode::first_node_value
std::string first_node_value(const char *nodeName=nullptr) const
Definition: RapidXmlReader.h:361
armarx::detail::Trace::PrintExceptionBacktrace
static void PrintExceptionBacktrace(std::ostream &out, const std::string &pre="")
Definition: trace.cpp:195
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:28
Exception.h
armarx::RapidXmlReaderNode::attribute_value_or_default
std::string attribute_value_or_default(const char *attrName, const std::string &defaultValue) const
Definition: RapidXmlReader.h:225
rapidxml_print.hpp
armarx::RapidXmlReader::getRoot
RapidXmlReaderNode getRoot(const char *name=nullptr)
Definition: RapidXmlReader.h:507