Visual Servoing Platform  version 3.6.1 under development (2024-03-28)
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 
55 vpXmlParser::vpXmlParser() : nodeMap(), main_tag("config") { }
56 
73 {
74  // xmlCleanupParser();
75 }
76 
82 vpXmlParser::vpXmlParser(const vpXmlParser &_twin) : nodeMap(_twin.nodeMap), main_tag(_twin.main_tag) { }
83 
84 /* utilities functions to read/write data from an xml document */
85 
97 char *vpXmlParser::xmlReadCharChild(xmlDocPtr doc, xmlNodePtr node)
98 {
99  if (node->xmlChildrenNode == nullptr) {
100  std::string errorMsg = "Empty node " + std::string((char *)node->name) + ", cannot read char*";
101  std::cerr << errorMsg << std::endl;
102  throw vpException(vpException::fatalError, errorMsg);
103  }
104  return (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
105 }
106 
117 std::string vpXmlParser::xmlReadStringChild(xmlDocPtr doc, xmlNodePtr node)
118 {
119  if (node->xmlChildrenNode == nullptr) {
120  std::string errorMsg = "Empty node " + std::string((char *)node->name) + ", cannot read std::string";
121  std::cerr << errorMsg << std::endl;
122  throw vpException(vpException::fatalError, errorMsg);
123  }
124  char *dataCh = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
125  std::string dataStr = dataCh;
126  xmlFree(dataCh);
127  return dataStr;
128 }
129 
141 int vpXmlParser::xmlReadIntChild(xmlDocPtr doc, xmlNodePtr node)
142 {
143  if (node->xmlChildrenNode == nullptr) {
144  std::string errorMsg = "Empty node " + std::string((char *)node->name) + ", cannot read int";
145  std::cerr << errorMsg << std::endl;
146  throw vpException(vpException::fatalError, errorMsg);
147  }
148  char *val_char;
149  char *control_convert;
150  int val_int;
151 
152  val_char = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
153  val_int = (int)strtol((char *)val_char, &control_convert, 10);
154 
155  if (val_char == control_convert) {
156  xmlFree((xmlChar *)val_char);
157  throw vpException(vpException::ioError, "cannot parse entry to int");
158  }
159  xmlFree((xmlChar *)val_char);
160 
161  return val_int;
162 }
163 
175 unsigned int vpXmlParser::xmlReadUnsignedIntChild(xmlDocPtr doc, xmlNodePtr node)
176 {
177  if (node->xmlChildrenNode == nullptr) {
178  std::string errorMsg = "Empty node " + std::string((char *)node->name) + ", cannot read unsigned int";
179  std::cerr << errorMsg << std::endl;
180  throw vpException(vpException::fatalError, errorMsg);
181  }
182  char *val_char;
183  char *control_convert;
184  unsigned int val_uint;
185 
186  val_char = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
187  val_uint = (unsigned int)strtoul((char *)val_char, &control_convert, 10);
188 
189  if (val_char == control_convert) {
190  xmlFree((xmlChar *)val_char);
191  throw vpException(vpException::ioError, "cannot parse entry to int");
192  }
193  xmlFree((xmlChar *)val_char);
194 
195  return val_uint;
196 }
197 
209 double vpXmlParser::xmlReadDoubleChild(xmlDocPtr doc, xmlNodePtr node)
210 {
211  if (node->xmlChildrenNode == nullptr) {
212  std::string errorMsg = "Empty node " + std::string((char *)node->name) + ", cannot read double";
213  std::cerr << errorMsg << std::endl;
214  throw vpException(vpException::fatalError, errorMsg);
215  }
216  char *val_char;
217  char *control_convert;
218  double val_double;
219 
220  val_char = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
221  val_double = strtod((char *)val_char, &control_convert);
222 
223  if (val_char == control_convert) {
224  xmlFree((xmlChar *)val_char);
225  throw vpException(vpException::ioError, "cannot parse entry to double");
226  }
227  xmlFree((xmlChar *)val_char);
228  return val_double;
229 }
230 
242 float vpXmlParser::xmlReadFloatChild(xmlDocPtr doc, xmlNodePtr node)
243 {
244  if (node->xmlChildrenNode == nullptr) {
245  std::string errorMsg = "Empty node " + std::string((char *)node->name) + ", cannot read float";
246  std::cerr << errorMsg << std::endl;
247  throw vpException(vpException::fatalError, errorMsg);
248  }
249  char *val_char;
250  char *control_convert;
251  float val_float;
252 
253  val_char = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
254 #if defined(VISP_HAVE_FUNC_STRTOF)
255  val_float = strtof((char *)val_char, &control_convert);
256 #else
257  val_float = (float)strtod((char *)val_char, &control_convert);
258 #endif
259 
260  if (val_char == control_convert) {
261  xmlFree((xmlChar *)val_char);
262  throw vpException(vpException::ioError, "cannot parse entry to float");
263  }
264  xmlFree((xmlChar *)val_char);
265  return val_float;
266 }
267 
279 bool vpXmlParser::xmlReadBoolChild(xmlDocPtr doc, xmlNodePtr node)
280 {
281  if (node->xmlChildrenNode == nullptr) {
282  std::string errorMsg = "Empty node " + std::string((char *)node->name) + ", cannot read bool";
283  std::cerr << errorMsg << std::endl;
284  throw vpException(vpException::fatalError, errorMsg);
285  }
286  char *val_char;
287  bool val_bool;
288 
289  val_char = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
290  val_bool = val_char[0] != '0'; // reading only 1st character : bool xml storage is '0' or '1'
291 
292  xmlFree((xmlChar *)val_char);
293  return val_bool;
294 }
295 
303 void vpXmlParser::xmlWriteCharChild(xmlNodePtr node, const char *label, const char *value)
304 {
305  xmlNodePtr tmp;
306  tmp = xmlNewChild(node, nullptr, (xmlChar *)label, (xmlChar *)value);
307  xmlAddChild(node, tmp);
308 }
309 
317 void vpXmlParser::xmlWriteStringChild(xmlNodePtr node, const char *label, const std::string &value)
318 {
319  xmlNodePtr tmp;
320  tmp = xmlNewChild(node, nullptr, (xmlChar *)label, (xmlChar *)value.c_str());
321  xmlAddChild(node, tmp);
322 }
323 
331 void vpXmlParser::xmlWriteIntChild(xmlNodePtr node, const char *label, int value)
332 {
333  char str[100];
334  snprintf(str, 100, "%d", value);
335  xmlNodePtr tmp;
336  tmp = xmlNewChild(node, nullptr, (xmlChar *)label, (xmlChar *)str);
337  xmlAddChild(node, tmp);
338 }
339 
347 void vpXmlParser::xmlWriteUnsignedIntChild(xmlNodePtr node, const char *label, unsigned int value)
348 {
349  char str[100];
350  snprintf(str, 100, "%u", value);
351  xmlNodePtr tmp;
352  tmp = xmlNewChild(node, nullptr, (xmlChar *)label, (xmlChar *)str);
353  xmlAddChild(node, tmp);
354 }
355 
363 void vpXmlParser::xmlWriteDoubleChild(xmlNodePtr node, const char *label, double value)
364 {
365  char str[100];
366  snprintf(str, 100, "%lf", value);
367  xmlNodePtr tmp;
368  tmp = xmlNewChild(node, nullptr, (xmlChar *)label, (xmlChar *)str);
369  xmlAddChild(node, tmp);
370 }
371 
379 void vpXmlParser::xmlWriteFloatChild(xmlNodePtr node, const char *label, float value)
380 {
381  char str[100];
382  snprintf(str, 100, "%f", value);
383  xmlNodePtr tmp;
384  tmp = xmlNewChild(node, nullptr, (xmlChar *)label, (xmlChar *)str);
385  xmlAddChild(node, tmp);
386 }
387 
395 void vpXmlParser::xmlWriteBoolChild(xmlNodePtr node, const char *label, bool value)
396 {
397  char str[2];
398  snprintf(str, 2, "%d", (int)value);
399  xmlNodePtr tmp;
400  tmp = xmlNewChild(node, nullptr, (xmlChar *)label, (xmlChar *)str);
401  xmlAddChild(node, tmp);
402 }
403 
404 /* --------------------------------------------------------------------------
405  */
406 /* MAIN METHODS */
407 /* --------------------------------------------------------------------------
408  */
409 
418 void vpXmlParser::parse(const std::string &filename)
419 {
420  xmlDocPtr doc;
421  xmlNodePtr root_node;
422 
423  doc = xmlParseFile(filename.c_str());
424  if (doc == nullptr) {
425  vpERROR_TRACE("cannot open file");
426  throw vpException(vpException::ioError, "cannot open file");
427  }
428 
429  root_node = xmlDocGetRootElement(doc);
430  if (root_node == nullptr) {
431  vpERROR_TRACE("cannot get root element");
432  throw vpException(vpException::ioError, "cannot get root element");
433  }
434 
435  readMainClass(doc, root_node);
436 
437  xmlFreeDoc(doc);
438 }
439 
450 void vpXmlParser::save(const std::string &filename, bool append)
451 {
452  xmlDocPtr doc;
453  xmlNodePtr root_node;
454 
455  doc = xmlReadFile(filename.c_str(), nullptr, XML_PARSE_NOWARNING + XML_PARSE_NOERROR + XML_PARSE_NOBLANKS);
456  if (doc == nullptr) {
457  doc = xmlNewDoc((xmlChar *)"1.0");
458  root_node = xmlNewNode(nullptr, (xmlChar *)main_tag.c_str());
459  xmlDocSetRootElement(doc, root_node);
460  }
461  else {
462  if (!append) {
463  xmlFreeDoc(doc);
464  if (remove(filename.c_str()) != 0)
465  throw vpException(vpException::ioError, "Cannot remove existing xml file");
466 
467  doc = xmlNewDoc((xmlChar *)"1.0");
468  root_node = xmlNewNode(nullptr, (xmlChar *)main_tag.c_str());
469  xmlDocSetRootElement(doc, root_node);
470  }
471  }
472 
473  root_node = xmlDocGetRootElement(doc);
474  if (root_node == nullptr) {
475  vpERROR_TRACE("problem to get the root node");
476  throw vpException(vpException::ioError, "problem to get the root node");
477  }
478 
479  writeMainClass(root_node);
480 
481  xmlSaveFormatFile(filename.c_str(), doc, 1);
482  xmlFreeDoc(doc);
483 }
484 
485 #elif !defined(VISP_BUILD_SHARED_LIBS)
486 // Work around to avoid warning: libvisp_core.a(vpXmlParser.cpp.o) has no symbols
487 void dummy_vpXmlParser() { };
488 #endif
error that can be emitted by ViSP classes.
Definition: vpException.h:59
@ ioError
I/O error.
Definition: vpException.h:79
@ fatalError
Fatal error.
Definition: vpException.h:84
void xmlWriteIntChild(xmlNodePtr node, const char *label, int value)
void xmlWriteBoolChild(xmlNodePtr node, const char *label, bool value)
void xmlWriteFloatChild(xmlNodePtr node, const char *label, float value)
double xmlReadDoubleChild(xmlDocPtr doc, xmlNodePtr node)
void xmlWriteDoubleChild(xmlNodePtr node, const char *label, double value)
float xmlReadFloatChild(xmlDocPtr doc, xmlNodePtr node)
void xmlWriteUnsignedIntChild(xmlNodePtr node, const char *label, unsigned int value)
void xmlWriteCharChild(xmlNodePtr node, const char *label, const char *value)
void xmlWriteStringChild(xmlNodePtr node, const char *label, const std::string &value)
int xmlReadIntChild(xmlDocPtr doc, xmlNodePtr node)
void save(const std::string &filename, bool append=false)
bool xmlReadBoolChild(xmlDocPtr doc, xmlNodePtr node)
unsigned int xmlReadUnsignedIntChild(xmlDocPtr doc, xmlNodePtr node)
virtual ~vpXmlParser()
Definition: vpXmlParser.cpp:72
void parse(const std::string &filename)
char * xmlReadCharChild(xmlDocPtr doc, xmlNodePtr node)
Definition: vpXmlParser.cpp:97
virtual void readMainClass(xmlDocPtr doc, xmlNodePtr node)=0
std::string xmlReadStringChild(xmlDocPtr doc, xmlNodePtr node)
virtual void writeMainClass(xmlNodePtr node)=0
std::string main_tag
Definition: vpXmlParser.h:230
#define vpERROR_TRACE
Definition: vpDebug.h:382