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
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 the document.
Save the content of the class in the file given in parameters.
set the name of the main tag
Set the map describing the data to parse.
Inherited Methods
Operators
__doc__
__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.
- 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.
- setMainTag(self, tag: str) None ¶
set the name of the main tag
The main tag corresponds to the name of the root node
- 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;