Visual Servoing Platform  version 3.6.1 under development (2024-11-15)
vpXmlParser.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See https://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Tool to automatize the creation of xml parser based on the libXML2.
33  *
34 *****************************************************************************/
35 
36 #include <visp3/core/vpConfig.h>
37 #include <visp3/core/vpXmlParser.h>
38 
39 #ifdef VISP_HAVE_XML2
40 
41 #include <libxml/parser.h>
42 #include <visp3/core/vpDebug.h>
43 #include <visp3/core/vpException.h>
44 
45 #include <iomanip>
46 #include <sstream>
47 #include <string>
48 #include <typeinfo>
49 
50 BEGIN_VISP_NAMESPACE
56 vpXmlParser::vpXmlParser() : nodeMap(), main_tag("config") { }
57 
73 vpXmlParser::~vpXmlParser()
74 {
75  // xmlCleanupParser();
76 }
77 
83 vpXmlParser::vpXmlParser(const vpXmlParser &_twin) : nodeMap(_twin.nodeMap), main_tag(_twin.main_tag) { }
84 
85 /* utilities functions to read/write data from an xml document */
86 
98 char *vpXmlParser::xmlReadCharChild(xmlDocPtr doc, xmlNodePtr node)
99 {
100  if (node->xmlChildrenNode == nullptr) {
101  std::string errorMsg = "Empty node " + std::string((char *)node->name) + ", cannot read char*";
102  std::cerr << errorMsg << std::endl;
103  throw vpException(vpException::fatalError, errorMsg);
104  }
105  return (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
106 }
107 
118 std::string vpXmlParser::xmlReadStringChild(xmlDocPtr doc, xmlNodePtr node)
119 {
120  if (node->xmlChildrenNode == nullptr) {
121  std::string errorMsg = "Empty node " + std::string((char *)node->name) + ", cannot read std::string";
122  std::cerr << errorMsg << std::endl;
123  throw vpException(vpException::fatalError, errorMsg);
124  }
125  char *dataCh = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
126  std::string dataStr = dataCh;
127  xmlFree(dataCh);
128  return dataStr;
129 }
130 
142 int vpXmlParser::xmlReadIntChild(xmlDocPtr doc, xmlNodePtr node)
143 {
144  if (node->xmlChildrenNode == nullptr) {
145  std::string errorMsg = "Empty node " + std::string((char *)node->name) + ", cannot read int";
146  std::cerr << errorMsg << std::endl;
147  throw vpException(vpException::fatalError, errorMsg);
148  }
149  char *val_char;
150  char *control_convert;
151  int val_int;
152 
153  val_char = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
154  val_int = (int)strtol((char *)val_char, &control_convert, 10);
155 
156  if (val_char == control_convert) {
157  xmlFree((xmlChar *)val_char);
158  throw vpException(vpException::ioError, "cannot parse entry to int");
159  }
160  xmlFree((xmlChar *)val_char);
161 
162  return val_int;
163 }
164 
176 unsigned int vpXmlParser::xmlReadUnsignedIntChild(xmlDocPtr doc, xmlNodePtr node)
177 {
178  if (node->xmlChildrenNode == nullptr) {
179  std::string errorMsg = "Empty node " + std::string((char *)node->name) + ", cannot read unsigned int";
180  std::cerr << errorMsg << std::endl;
181  throw vpException(vpException::fatalError, errorMsg);
182  }
183  char *val_char;
184  char *control_convert;
185  unsigned int val_uint;
186 
187  val_char = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
188  val_uint = (unsigned int)strtoul((char *)val_char, &control_convert, 10);
189 
190  if (val_char == control_convert) {
191  xmlFree((xmlChar *)val_char);
192  throw vpException(vpException::ioError, "cannot parse entry to int");
193  }
194  xmlFree((xmlChar *)val_char);
195 
196  return val_uint;
197 }
198 
210 double vpXmlParser::xmlReadDoubleChild(xmlDocPtr doc, xmlNodePtr node)
211 {
212  if (node->xmlChildrenNode == nullptr) {
213  std::string errorMsg = "Empty node " + std::string((char *)node->name) + ", cannot read double";
214  std::cerr << errorMsg << std::endl;
215  throw vpException(vpException::fatalError, errorMsg);
216  }
217  char *val_char;
218  char *control_convert;
219  double val_double;
220 
221  val_char = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
222  val_double = strtod((char *)val_char, &control_convert);
223 
224  if (val_char == control_convert) {
225  xmlFree((xmlChar *)val_char);
226  throw vpException(vpException::ioError, "cannot parse entry to double");
227  }
228  xmlFree((xmlChar *)val_char);
229  return val_double;
230 }
231 
243 float vpXmlParser::xmlReadFloatChild(xmlDocPtr doc, xmlNodePtr node)
244 {
245  if (node->xmlChildrenNode == nullptr) {
246  std::string errorMsg = "Empty node " + std::string((char *)node->name) + ", cannot read float";
247  std::cerr << errorMsg << std::endl;
248  throw vpException(vpException::fatalError, errorMsg);
249  }
250  char *val_char;
251  char *control_convert;
252  float val_float;
253 
254  val_char = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
255 #if defined(VISP_HAVE_FUNC_STRTOF)
256  val_float = strtof((char *)val_char, &control_convert);
257 #else
258  val_float = (float)strtod((char *)val_char, &control_convert);
259 #endif
260 
261  if (val_char == control_convert) {
262  xmlFree((xmlChar *)val_char);
263  throw vpException(vpException::ioError, "cannot parse entry to float");
264  }
265  xmlFree((xmlChar *)val_char);
266  return val_float;
267 }
268 
280 bool vpXmlParser::xmlReadBoolChild(xmlDocPtr doc, xmlNodePtr node)
281 {
282  if (node->xmlChildrenNode == nullptr) {
283  std::string errorMsg = "Empty node " + std::string((char *)node->name) + ", cannot read bool";
284  std::cerr << errorMsg << std::endl;
285  throw vpException(vpException::fatalError, errorMsg);
286  }
287  char *val_char;
288  bool val_bool;
289 
290  val_char = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
291  val_bool = val_char[0] != '0'; // reading only 1st character : bool xml storage is '0' or '1'
292 
293  xmlFree((xmlChar *)val_char);
294  return val_bool;
295 }
296 
304 void vpXmlParser::xmlWriteCharChild(xmlNodePtr node, const char *label, const char *value)
305 {
306  xmlNodePtr tmp;
307  tmp = xmlNewChild(node, nullptr, (xmlChar *)label, (xmlChar *)value);
308  xmlAddChild(node, tmp);
309 }
310 
318 void vpXmlParser::xmlWriteStringChild(xmlNodePtr node, const char *label, const std::string &value)
319 {
320  xmlNodePtr tmp;
321  tmp = xmlNewChild(node, nullptr, (xmlChar *)label, (xmlChar *)value.c_str());
322  xmlAddChild(node, tmp);
323 }
324 
332 void vpXmlParser::xmlWriteIntChild(xmlNodePtr node, const char *label, int value)
333 {
334  char str[100];
335  snprintf(str, 100, "%d", value);
336  xmlNodePtr tmp;
337  tmp = xmlNewChild(node, nullptr, (xmlChar *)label, (xmlChar *)str);
338  xmlAddChild(node, tmp);
339 }
340 
348 void vpXmlParser::xmlWriteUnsignedIntChild(xmlNodePtr node, const char *label, unsigned int value)
349 {
350  char str[100];
351  snprintf(str, 100, "%u", value);
352  xmlNodePtr tmp;
353  tmp = xmlNewChild(node, nullptr, (xmlChar *)label, (xmlChar *)str);
354  xmlAddChild(node, tmp);
355 }
356 
364 void vpXmlParser::xmlWriteDoubleChild(xmlNodePtr node, const char *label, double value)
365 {
366  char str[100];
367  snprintf(str, 100, "%lf", value);
368  xmlNodePtr tmp;
369  tmp = xmlNewChild(node, nullptr, (xmlChar *)label, (xmlChar *)str);
370  xmlAddChild(node, tmp);
371 }
372 
380 void vpXmlParser::xmlWriteFloatChild(xmlNodePtr node, const char *label, float value)
381 {
382  char str[100];
383  snprintf(str, 100, "%f", value);
384  xmlNodePtr tmp;
385  tmp = xmlNewChild(node, nullptr, (xmlChar *)label, (xmlChar *)str);
386  xmlAddChild(node, tmp);
387 }
388 
396 void vpXmlParser::xmlWriteBoolChild(xmlNodePtr node, const char *label, bool value)
397 {
398  char str[2];
399  snprintf(str, 2, "%d", (int)value);
400  xmlNodePtr tmp;
401  tmp = xmlNewChild(node, nullptr, (xmlChar *)label, (xmlChar *)str);
402  xmlAddChild(node, tmp);
403 }
404 
405 /* --------------------------------------------------------------------------
406  */
407 /* MAIN METHODS */
408 /* --------------------------------------------------------------------------
409  */
410 
419 void vpXmlParser::parse(const std::string &filename)
420 {
421  xmlDocPtr doc;
422  xmlNodePtr root_node;
423 
424  doc = xmlParseFile(filename.c_str());
425  if (doc == nullptr) {
426  vpERROR_TRACE("cannot open file");
427  throw vpException(vpException::ioError, "cannot open file");
428  }
429 
430  root_node = xmlDocGetRootElement(doc);
431  if (root_node == nullptr) {
432  vpERROR_TRACE("cannot get root element");
433  throw vpException(vpException::ioError, "cannot get root element");
434  }
435 
436  readMainClass(doc, root_node);
437 
438  xmlFreeDoc(doc);
439 }
440 
451 void vpXmlParser::save(const std::string &filename, bool append)
452 {
453  xmlDocPtr doc;
454  xmlNodePtr root_node;
455 
456  doc = xmlReadFile(filename.c_str(), nullptr, XML_PARSE_NOWARNING + XML_PARSE_NOERROR + XML_PARSE_NOBLANKS);
457  if (doc == nullptr) {
458  doc = xmlNewDoc((xmlChar *)"1.0");
459  root_node = xmlNewNode(nullptr, (xmlChar *)main_tag.c_str());
460  xmlDocSetRootElement(doc, root_node);
461  }
462  else {
463  if (!append) {
464  xmlFreeDoc(doc);
465  if (remove(filename.c_str()) != 0)
466  throw vpException(vpException::ioError, "Cannot remove existing xml file");
467 
468  doc = xmlNewDoc((xmlChar *)"1.0");
469  root_node = xmlNewNode(nullptr, (xmlChar *)main_tag.c_str());
470  xmlDocSetRootElement(doc, root_node);
471  }
472  }
473 
474  root_node = xmlDocGetRootElement(doc);
475  if (root_node == nullptr) {
476  vpERROR_TRACE("problem to get the root node");
477  throw vpException(vpException::ioError, "problem to get the root node");
478  }
479 
480  writeMainClass(root_node);
481 
482  xmlSaveFormatFile(filename.c_str(), doc, 1);
483  xmlFreeDoc(doc);
484 }
485 END_VISP_NAMESPACE
486 #elif !defined(VISP_BUILD_SHARED_LIBS)
487 // Work around to avoid warning: libvisp_core.a(vpXmlParser.cpp.o) has no symbols
488 void dummy_vpXmlParser() { };
489 #endif
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ ioError
I/O error.
Definition: vpException.h:67
@ fatalError
Fatal error.
Definition: vpException.h:72