Visual Servoing Platform  version 3.4.1 under development (2021-04-20)
vpXmlParser.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 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 http://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 automatise the creation of xml parser based on the libXML2
33  *
34  * Authors:
35  * Romain Tallonneau
36  *
37  *****************************************************************************/
38 
39 #include <visp3/core/vpConfig.h>
40 #include <visp3/core/vpXmlParser.h>
41 
42 #ifdef VISP_HAVE_XML2
43 
44 #include <libxml/parser.h>
45 #include <visp3/core/vpDebug.h>
46 #include <visp3/core/vpException.h>
47 
48 #include <iomanip>
49 #include <sstream>
50 #include <string>
51 #include <typeinfo>
52 
58 vpXmlParser::vpXmlParser() : nodeMap(), main_tag("config") {}
59 
76 {
77  // xmlCleanupParser();
78 }
79 
86 
87 /* utilities functions to read/write data from an xml document */
88 
100 char *vpXmlParser::xmlReadCharChild(xmlDocPtr doc, xmlNodePtr node)
101 {
102  if (node->xmlChildrenNode == NULL) {
103  std::string errorMsg = "Empty node " + std::string((char *)node->name) + ", cannot read char*";
104  std::cerr << errorMsg << std::endl;
105  throw vpException(vpException::fatalError, errorMsg);
106  }
107  return (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
108 }
109 
120 std::string vpXmlParser::xmlReadStringChild(xmlDocPtr doc, xmlNodePtr node)
121 {
122  if (node->xmlChildrenNode == NULL) {
123  std::string errorMsg = "Empty node " + std::string((char *)node->name) + ", cannot read std::string";
124  std::cerr << errorMsg << std::endl;
125  throw vpException(vpException::fatalError, errorMsg);
126  }
127  char *dataCh = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
128  std::string dataStr = dataCh;
129  xmlFree(dataCh);
130  return dataStr;
131 }
132 
144 int vpXmlParser::xmlReadIntChild(xmlDocPtr doc, xmlNodePtr node)
145 {
146  if (node->xmlChildrenNode == NULL) {
147  std::string errorMsg = "Empty node " + std::string((char *)node->name) + ", cannot read int";
148  std::cerr << errorMsg << std::endl;
149  throw vpException(vpException::fatalError, errorMsg);
150  }
151  char *val_char;
152  char *control_convert;
153  int val_int;
154 
155  val_char = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
156  val_int = (int)strtol((char *)val_char, &control_convert, 10);
157 
158  if (val_char == control_convert) {
159  xmlFree((xmlChar *)val_char);
160  throw vpException(vpException::ioError, "cannot parse entry to int");
161  }
162  xmlFree((xmlChar *)val_char);
163 
164  return val_int;
165 }
166 
178 unsigned int vpXmlParser::xmlReadUnsignedIntChild(xmlDocPtr doc, xmlNodePtr node)
179 {
180  if (node->xmlChildrenNode == NULL) {
181  std::string errorMsg = "Empty node " + std::string((char *)node->name) + ", cannot read unsigned int";
182  std::cerr << errorMsg << std::endl;
183  throw vpException(vpException::fatalError, errorMsg);
184  }
185  char *val_char;
186  char *control_convert;
187  unsigned int val_uint;
188 
189  val_char = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
190  val_uint = (unsigned int)strtoul((char *)val_char, &control_convert, 10);
191 
192  if (val_char == control_convert) {
193  xmlFree((xmlChar *)val_char);
194  throw vpException(vpException::ioError, "cannot parse entry to int");
195  }
196  xmlFree((xmlChar *)val_char);
197 
198  return val_uint;
199 }
200 
212 double vpXmlParser::xmlReadDoubleChild(xmlDocPtr doc, xmlNodePtr node)
213 {
214  if (node->xmlChildrenNode == NULL) {
215  std::string errorMsg = "Empty node " + std::string((char *)node->name) + ", cannot read double";
216  std::cerr << errorMsg << std::endl;
217  throw vpException(vpException::fatalError, errorMsg);
218  }
219  char *val_char;
220  char *control_convert;
221  double val_double;
222 
223  val_char = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
224  val_double = strtod((char *)val_char, &control_convert);
225 
226  if (val_char == control_convert) {
227  xmlFree((xmlChar *)val_char);
228  throw vpException(vpException::ioError, "cannot parse entry to double");
229  }
230  xmlFree((xmlChar *)val_char);
231  return val_double;
232 }
233 
245 float vpXmlParser::xmlReadFloatChild(xmlDocPtr doc, xmlNodePtr node)
246 {
247  if (node->xmlChildrenNode == NULL) {
248  std::string errorMsg = "Empty node " + std::string((char *)node->name) + ", cannot read float";
249  std::cerr << errorMsg << std::endl;
250  throw vpException(vpException::fatalError, errorMsg);
251  }
252  char *val_char;
253  char *control_convert;
254  float val_float;
255 
256  val_char = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
257 #if defined(VISP_HAVE_FUNC_STRTOF)
258  val_float = strtof((char *)val_char, &control_convert);
259 #else
260  val_float = (float)strtod((char *)val_char, &control_convert);
261 #endif
262 
263  if (val_char == control_convert) {
264  xmlFree((xmlChar *)val_char);
265  throw vpException(vpException::ioError, "cannot parse entry to float");
266  }
267  xmlFree((xmlChar *)val_char);
268  return val_float;
269 }
270 
282 bool vpXmlParser::xmlReadBoolChild(xmlDocPtr doc, xmlNodePtr node)
283 {
284  if (node->xmlChildrenNode == NULL) {
285  std::string errorMsg = "Empty node " + std::string((char *)node->name) + ", cannot read bool";
286  std::cerr << errorMsg << std::endl;
287  throw vpException(vpException::fatalError, errorMsg);
288  }
289  char *val_char;
290  bool val_bool;
291 
292  val_char = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
293  val_bool = val_char[0] != '0'; // reading only 1st character : bool xml storage is '0' or '1'
294 
295  xmlFree((xmlChar *)val_char);
296  return val_bool;
297 }
298 
306 void vpXmlParser::xmlWriteCharChild(xmlNodePtr node, const char *label, const char *value)
307 {
308  xmlNodePtr tmp;
309  tmp = xmlNewChild(node, NULL, (xmlChar *)label, (xmlChar *)value);
310  xmlAddChild(node, tmp);
311 }
312 
320 void vpXmlParser::xmlWriteStringChild(xmlNodePtr node, const char *label, const std::string &value)
321 {
322  xmlNodePtr tmp;
323  tmp = xmlNewChild(node, NULL, (xmlChar *)label, (xmlChar *)value.c_str());
324  xmlAddChild(node, tmp);
325 }
326 
334 void vpXmlParser::xmlWriteIntChild(xmlNodePtr node, const char *label, int value)
335 {
336  char str[100];
337  sprintf(str, "%d", value);
338  xmlNodePtr tmp;
339  tmp = xmlNewChild(node, NULL, (xmlChar *)label, (xmlChar *)str);
340  xmlAddChild(node, tmp);
341 }
342 
350 void vpXmlParser::xmlWriteUnsignedIntChild(xmlNodePtr node, const char *label, unsigned int value)
351 {
352  char str[100];
353  sprintf(str, "%u", value);
354  xmlNodePtr tmp;
355  tmp = xmlNewChild(node, NULL, (xmlChar *)label, (xmlChar *)str);
356  xmlAddChild(node, tmp);
357 }
358 
366 void vpXmlParser::xmlWriteDoubleChild(xmlNodePtr node, const char *label, double value)
367 {
368  char str[100];
369  sprintf(str, "%lf", value);
370  xmlNodePtr tmp;
371  tmp = xmlNewChild(node, NULL, (xmlChar *)label, (xmlChar *)str);
372  xmlAddChild(node, tmp);
373 }
374 
382 void vpXmlParser::xmlWriteFloatChild(xmlNodePtr node, const char *label, float value)
383 {
384  char str[100];
385  sprintf(str, "%f", value);
386  xmlNodePtr tmp;
387  tmp = xmlNewChild(node, NULL, (xmlChar *)label, (xmlChar *)str);
388  xmlAddChild(node, tmp);
389 }
390 
398 void vpXmlParser::xmlWriteBoolChild(xmlNodePtr node, const char *label, bool value)
399 {
400  char str[2];
401  sprintf(str, "%d", (int)value);
402  xmlNodePtr tmp;
403  tmp = xmlNewChild(node, NULL, (xmlChar *)label, (xmlChar *)str);
404  xmlAddChild(node, tmp);
405 }
406 
407 /* --------------------------------------------------------------------------
408  */
409 /* MAIN METHODS */
410 /* --------------------------------------------------------------------------
411  */
412 
421 void vpXmlParser::parse(const std::string &filename)
422 {
423  xmlDocPtr doc;
424  xmlNodePtr root_node;
425 
426  doc = xmlParseFile(filename.c_str());
427  if (doc == NULL) {
428  vpERROR_TRACE("cannot open file");
429  throw vpException(vpException::ioError, "cannot open file");
430  }
431 
432  root_node = xmlDocGetRootElement(doc);
433  if (root_node == NULL) {
434  vpERROR_TRACE("cannot get root element");
435  throw vpException(vpException::ioError, "cannot get root element");
436  }
437 
438  readMainClass(doc, root_node);
439 
440  xmlFreeDoc(doc);
441 }
442 
453 void vpXmlParser::save(const std::string &filename, bool append)
454 {
455  xmlDocPtr doc;
456  xmlNodePtr root_node;
457 
458  doc = xmlReadFile(filename.c_str(), NULL, XML_PARSE_NOWARNING + XML_PARSE_NOERROR + XML_PARSE_NOBLANKS);
459  if (doc == NULL) {
460  doc = xmlNewDoc((xmlChar *)"1.0");
461  root_node = xmlNewNode(NULL, (xmlChar *)main_tag.c_str());
462  xmlDocSetRootElement(doc, root_node);
463  } else {
464  if (!append) {
465  xmlFreeDoc(doc);
466  if (remove(filename.c_str()) != 0)
467  throw vpException(vpException::ioError, "Cannot remove existing xml file");
468 
469  doc = xmlNewDoc((xmlChar *)"1.0");
470  root_node = xmlNewNode(NULL, (xmlChar *)main_tag.c_str());
471  xmlDocSetRootElement(doc, root_node);
472  }
473  }
474 
475  root_node = xmlDocGetRootElement(doc);
476  if (root_node == NULL) {
477  vpERROR_TRACE("problem to get the root node");
478  throw vpException(vpException::ioError, "problem to get the root node");
479  }
480 
481  writeMainClass(root_node);
482 
483  xmlSaveFormatFile(filename.c_str(), doc, 1);
484  xmlFreeDoc(doc);
485 }
486 
487 #elif !defined(VISP_BUILD_SHARED_LIBS)
488 // Work arround to avoid warning: libvisp_core.a(vpXmlParser.cpp.o) has no
489 // symbols
490 void dummy_vpXmlParser(){};
491 #endif
std::string main_tag
Definition: vpXmlParser.h:235
void xmlWriteIntChild(xmlNodePtr node, const char *label, int value)
virtual ~vpXmlParser()
Definition: vpXmlParser.cpp:75
void xmlWriteUnsignedIntChild(xmlNodePtr node, const char *label, unsigned int value)
#define vpERROR_TRACE
Definition: vpDebug.h:393
error that can be emited by ViSP classes.
Definition: vpException.h:71
virtual void writeMainClass(xmlNodePtr node)=0
double xmlReadDoubleChild(xmlDocPtr doc, xmlNodePtr node)
char * xmlReadCharChild(xmlDocPtr doc, xmlNodePtr node)
void xmlWriteCharChild(xmlNodePtr node, const char *label, const char *value)
int xmlReadIntChild(xmlDocPtr doc, xmlNodePtr node)
void xmlWriteBoolChild(xmlNodePtr node, const char *label, bool value)
void xmlWriteFloatChild(xmlNodePtr node, const char *label, float value)
virtual void readMainClass(xmlDocPtr doc, xmlNodePtr node)=0
void xmlWriteDoubleChild(xmlNodePtr node, const char *label, double value)
unsigned int xmlReadUnsignedIntChild(xmlDocPtr doc, xmlNodePtr node)
std::string xmlReadStringChild(xmlDocPtr doc, xmlNodePtr node)
float xmlReadFloatChild(xmlDocPtr doc, xmlNodePtr node)
void xmlWriteStringChild(xmlNodePtr node, const char *label, const std::string &value)
bool xmlReadBoolChild(xmlDocPtr doc, xmlNodePtr node)
void save(const std::string &filename, bool append=false)
std::map< std::string, int > nodeMap
Definition: vpXmlParser.h:230
void parse(const std::string &filename)