XmlParser

class XmlParser

Bases: pybind11_object

This class intends to simplify the creation of xml parser based on the libxml2 third party library.

This class can be useful to manage external data parameters (for example for configuration of an experiment, …).

Warning

This class is only available if libxml2 is installed and detected by ViSP. Installation instructions are provided here https://visp.inria.fr/3rd_xml2 .

Note

After ViSP 3.2.0 release we introduce pugixml built-in 3rd party library that replaces favorably libxml2. For example vpXmlParserCamera uses now pugixml instead of inheriting from vpXmlParser .

In order to use this class, you have to create a new class inheriting from this one. In the child class, you have to implement the methods:

  • writeMainClass()

  • readMainClass()

These two methods depends on the data to parse, and must not be directly called (they are called from the parse() and the save() methods).

Following is an example of implementation for the document:

<config>
    <range>5</range>
    <step>7</step>
    <size_filter>3</size_filter>
</config>

A class to parse this document is declared as follows:

class vpDataParser: public vpXmlParser
{
private:
  int m_range;
  int m_step;
  int m_size_filter
public:
  typedef enum{
    config,
    range,
    step,
    size_filter
  }dataToParse

  vpDataParser(){
    nodeMap["config"] = config;
    nodeMap["range"] = range;
    nodeMap["step"] = step;
    nodeMap["size_filter"] = size_filter;
  }

  virtual void writeMainClass(xmlNodePtr node);
  virtual void readMainClass(xmlDocPtr doc, xmlNodePtr node);

  // additionals methods specific to the data to parse
  // such as: accessors
}

The readMainClass function implementation is:

void
vpDataParser::readMainClass(xmlDocPtr doc, xmlNodePtr node)
{
  for (xmlNodePtr tmpNode = node->xmlChildrenNode; tmpNode != nullptr; tmpNode = tmpNode->next) {
    if(tmpNode->type == XML_ELEMENT_NODE) {

      std::map<std::string, int>::iterator iter = this->nodeMap.find((char*)tmpNode->name);
      if(iter == nodeMap.end()) {
        continue;
      }

      switch (iter->second){
      case range:
        this->m_range = xmlReadIntChild(doc, tmpNode);
        break;
      case step:
        this->m_step = xmlReadIntChild(doc, tmpNode);
        break;
      case size_filter:
        this->m_size_filter = xmlReadIntChild(doc, tmpNode);
        break;
      default:
        std::cout << "problem in the readMainClass (" << iter->second
                  << " , " << iter->first << " )" << std::endl; break;
      }
    }
  }
}

Data can now be accessed through the internal variables of the class vpDataParser.

To store the data in a xml file, the function save has to be called. This function needs the implementation of the writeMainClass function.

For example,

void
vpDataParser::writeMainClass(xmlNodePtr node)
{
  xmlWriteIntChild(node, "range", m_range);
  xmlWriteIntChild(node, "step", m_step);
  xmlWriteIntChild(node, "size_filter", m_size_filter);
}

Methods

__init__

cleanup

As stated in http://xmlsoft.org/html/libxml-parser.html#xmlCleanupParser to clean up memory allocated by the xml2 library itself, the user should call xmlCleanupParser() only when the process has finished using the xml2 library.

parse

parse the document.

save

Save the content of the class in the file given in parameters.

setMainTag

set the name of the main tag

setMap

Set the map describing the data to parse.

Inherited Methods

Operators

__doc__

__init__

__module__

Attributes

__annotations__

__init__(*args, **kwargs)
static cleanup() None

As stated in http://xmlsoft.org/html/libxml-parser.html#xmlCleanupParser to clean up memory allocated by the xml2 library itself, the user should call xmlCleanupParser() only when the process has finished using the xml2 library. In case of doubt abstain from calling this function or do it just before calling exit() to avoid leak reports from valgrind ! That’s why in ViSP the destructor doesn’t call xmlCleanupParser(). Rather we provide the static function vpXmlParser::cleanup() that calls xmlCleanupParser() that could be called just before exit().

parse(self, filename: str) None

parse the document. The data in the file are stored in the attributes of the child class. This method calls the readMainClass method which has to be implemented for every child class depending on the content to parse.

Parameters:
filename: str

name of the file to parse

save(self, filename: str, append: bool = false) None

Save the content of the class in the file given in parameters. The data of the class are in the child class. This method calls the write_main_class method which has to be implemented for every class depending on the data to save.

Parameters:
filename: str

the name of the file used to record the data

append: bool = false

if true and if the file exists, the data will be added to the data already in the file

setMainTag(self, tag: str) None

set the name of the main tag

The main tag corresponds to the name of the root node

Parameters:
tag: str

name of the root node of the document

setMap(self, _map: dict[str, int]) None

Set the map describing the data to parse. This map stores the name of each node and an associated key used to simplify the parsing of the file.

If the following file want to be parsed:

<config>
  <range>5</range>
  <step>7</step>
  <size_filter>3</size_filter>
</config>

The following map has to be declared:

std::map dataToParse;
dataToParse["config"] = 0;
dataToParse["range"] = 1;
dataToParse["step"] = 2;
dataToParse["size_filter"] = 3;

Or, you can use keyzord instead of number as key but it implies to declare in the child class an enumeration type of the name. For example:

typedef enum{
  config,
  range,
  step,
  size_filter} data_enum;

std::map dataToParse;
dataToParse["config"] = config;
dataToParse["range"] = range;
dataToParse["step"] = step;
dataToParse["size_filter"] = size_filter;
Parameters:
_map: dict[str, int]

the map describing the data to parse