📜 ⬆️ ⬇️

Boost Property Tree and its XML parser

image

What is this article about


The article tells about the library Property Tree Library, namely:



Property tree


In Boost, starting from version 1.41.1, the Property Tree library has appeared. This library provides a new data type, the tree structure boost :: propetry_tree :: ptree.
')
A ptree is a regular tree structure, each element of which, in addition to data, can contain an ordered list of child elements, each of which has its own name.

The structure looks like this:
struct ptree { data_type data; //   list<pair<key_type, ptree>> children; //     }; 


Basically, a regular string is used as key_type.

Property Tree Usage Examples


The ptree structure is very convenient for reading, writing, saving and loading tree data.
Adding elements to this tree is easy:
 boost::property_tree::ptree heroTree; heroTree.put("Name", "John"); heroTree.put("Exp", 150); heroTree.put("Inventory.Weapon", "Blue Sword"); heroTree.put("Inventory.Money", 3000); 


Since ptree contains a linked list, you can add several items that have one key:
 heroTree.put("Inventory.Item", "Stone"); heroTree.put("Inventory.Item", "Golden helmet"); heroTree.put("Inventory.Item", "Thomb key"); 


Would you like to get a sub-tree? Nothing too complicated:
 boost::property_tree::ptree inventoryTree = heroTree.get_child("Inventory"); inventoryTree.put("Item", "Shield of Honor"); 


Getting items is also easy:
 int exp = pt.get<int>("Exp"); std::string weapon = pt.get<std::string>("Inventory.Weapon"); 


If the item is not found, an exception is thrown. If you do not want this, simply set the second parameter to the value you want to see by default:
 int exp = pt.get<int>("Exp", 0); 


If several elements are expected, you will have to sort through them:
 BOOST_FOREACH(auto &v, inventoryTree) { if (v.first == "Item") { std::cout << "Hero has item: " << v.second.get<std::string>("") << std::endl; } } 


XML parser


The great thing about the Property Tree Library is that the library contains built-in XML and JSON parsers. Parsers are not perfect, but they work right out of the box - no need to pull any additional libraries and dependencies.
I did not work with the JSON parser, but I use the XML parser to its fullest. About him and write more.

For reading xml and writing xml, the read_xml and write_xml methods are used, respectively. The use is very simple:
 //XML-   std::string xmlCode = "<ButtonList>\ <Button>B1</Button>\ <Button>B2</Button>\ </ButtonList>"; //  std::stringstream stream(xmlCode); try { boost::property_tree::ptree propertyTree; // XML boost::property_tree::read_xml(stream, propertyTree); // : BOOST_FOREACH(auto &v, propertyTree) { std::cout << "Button is " << v.second.get<std::string>("") << std::endl; } //   propertyTree.put("ButtonList.Button", "B3"); propertyTree.put("ButtonList.Button", "B4"); std::stringstream output_stream; //    boost::property_tree::write_xml(output_stream, propertyTree); // XML   std::string outputXmlCode = output_stream; } catch(boost::property_tree::xml_parser_error) { std::cout<<"XML parser error!"<<std::endl; throw; } 


If there is a need to read the node attribute, then this can be done through the pseudo-subtree "<xmlattr>":
 //XML-   std::string xmlCode = "<Data name="Position" x="5" y="5"/>"; //...  XML //  std::string name = propertyTree.get<std::string>("Data.<xmlattr>.name"); int x = propertyTree.get<std::string>("Data.<xmlattr>.x"); int y = propertyTree.get<std::string>("Data.<xmlattr>.y"); 


A small rake is associated with the pseudo-subtree "<xmlattr>", which can be inadvertently stepped on. Suppose, as in the above example, you have a ButtonList element in which there are 4 Button elements - these are the elements that characterize the buttons.
If the ButtonList element does not have attributes, then in the tree created on the basis of XML there will be 4 subtrees with buttons, as it should be. If the ButtonList has any attributes, then it's a surprise! - another subtree is added to 4 subtrees with buttons, with the key "<xmlattr>", which, obviously, has nothing to do with buttons.
If we go through all the subtrees, then together with the buttons we will try to process "<xmlattr>", and this will cause an error.
Therefore, when iterating over child trees, you will have to do an additional check that will exclude <xmlattr> from the search list. For example:
 BOOST_FOREACH(auto &v, propertyTree) { if (v.first == "Button") //   { std::cout << "Button is " << v.second.get<std::string>("") << std::endl; } } 


Other


In addition to the XML parser, Property Tree Library also contains JSON, INI, and INFO parsers. I did not understand them yet, but I suppose that everything is about the same there.

References:


www.boost.org/doc/libs/1_52_0/doc/html/property_tree.html

Source: https://habr.com/ru/post/168951/


All Articles