Boost Property_Tree iterators, how to handle them?
Asked Answered
J

3

15

I am sorry, I asked a question about the same topic before, but my problem concerns another aspect of the one described there (How to iterate a boost...).

Take a look at the following code:

#include <iostream>
#include <string>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/algorithm/string/trim.hpp>
int main(int argc, char** argv) {
     using boost::property_tree::ptree;
     ptree pt;
     read_xml("try.xml", pt);
     ptree::const_iterator end = pt.end();
     for (ptree::const_iterator it = pt.begin(); it != end; it++)
           std::cout << "Here " << it->? << std::endl;
}

Well, as I got told told in the question I mentioned, there is the possibility to use iterators on property_tree in Boost, but I do not know what type it is, and what methods or properties I can use.

Well, I assume that it must be another ptree or something representing another xml hierarchy to be browsed again (if I want) but documentation about this is very bad. I do not know why, but in boost docs I cannot find nothing good, just something about a macro to browse nodes, but this approach is one I would really like to avoid.

So getting to my question here: Once getting the iterator on a ptree, how can I access node name, value, parameters (a node in a xml file)? Thankyou

Johnathanjohnathon answered 4/1, 2011 at 18:30 Comment(0)
R
18

I agree with Andry, and find the documentation of property_tree to be extremely minimal at the least. I needed ptree for loading identical objects with different settings, and had trouble figuring out what the iterator iterates over, what type it returns, and whether or not it will remain on the objects level, or go through every node BFS-like. Finally, I managed to get my code working for a case similar to the following:

settings file:

<object1>
    <enable>true</enable>
    <label>hello</label>
</object1>
<object2>
    <enable>false</enable>
    <label>goodbye</label>
</object2>

First, I added a constructor for my object, which can initialize on a ptree. Note that I'm using the get with default option, to prevent exception on failed get()'s:

object::object(const boost::property_tree::ptree &pt_)
{
    enable = pt_.get<bool>("enable", true); // usage is: get<type>(path, default)
    label  = pt_.get<std::string>("label", "empty");
}

Finally the following code loads both objects, and places them in a map:

std::map<std::string, my_object> objects_map;

// parse settings file and add loggers
if(filesystem::exists(logger_settings_file))
{
    boost::property_tree::ptree pt;

    read_xml(logger_settings_file, pt);
    BOOST_FOREACH(boost::property_tree::ptree::value_type &v, pt)
    {
        objects_map[v.first] = my_object(v.second);
    }
}

So, to answer my own questions:

  • The iterator iterates over the settings file without descending into lower levels. Running the above code you will find that the loop iterates twice - one time for each object in the XML file.
  • The iterator returns a value_type object which resembles a pair, and has the first and second accessors. v.first is an std::string holding the parent node (in my case "object1", "object2"), and v.second is a boost::property_tree::ptree, which can be used to parse the fields of the object.
Retail answered 23/1, 2011 at 18:48 Comment(1)
Thank you bavaza... your answer explained a better approach... I liked it. Thank youJohnathanjohnathon
S
19

print complete tree:

void print(boost::property_tree::ptree const& pt)
{
    using boost::property_tree::ptree;
    ptree::const_iterator end = pt.end();
    for (ptree::const_iterator it = pt.begin(); it != end; ++it) {
        std::cout << it->first << ": " << it->second.get_value<std::string>() << std::endl;
        print(it->second);
    }
}
Salonika answered 4/1, 2011 at 20:51 Comment(2)
Hi, I just rejected an anonymous edit on this post (as it changes your code). You may want to check it out to see if it should be incorporated into your answer.Saxena
@Benjol: tnx. It was fine so I incorporated it.Salonika
R
18

I agree with Andry, and find the documentation of property_tree to be extremely minimal at the least. I needed ptree for loading identical objects with different settings, and had trouble figuring out what the iterator iterates over, what type it returns, and whether or not it will remain on the objects level, or go through every node BFS-like. Finally, I managed to get my code working for a case similar to the following:

settings file:

<object1>
    <enable>true</enable>
    <label>hello</label>
</object1>
<object2>
    <enable>false</enable>
    <label>goodbye</label>
</object2>

First, I added a constructor for my object, which can initialize on a ptree. Note that I'm using the get with default option, to prevent exception on failed get()'s:

object::object(const boost::property_tree::ptree &pt_)
{
    enable = pt_.get<bool>("enable", true); // usage is: get<type>(path, default)
    label  = pt_.get<std::string>("label", "empty");
}

Finally the following code loads both objects, and places them in a map:

std::map<std::string, my_object> objects_map;

// parse settings file and add loggers
if(filesystem::exists(logger_settings_file))
{
    boost::property_tree::ptree pt;

    read_xml(logger_settings_file, pt);
    BOOST_FOREACH(boost::property_tree::ptree::value_type &v, pt)
    {
        objects_map[v.first] = my_object(v.second);
    }
}

So, to answer my own questions:

  • The iterator iterates over the settings file without descending into lower levels. Running the above code you will find that the loop iterates twice - one time for each object in the XML file.
  • The iterator returns a value_type object which resembles a pair, and has the first and second accessors. v.first is an std::string holding the parent node (in my case "object1", "object2"), and v.second is a boost::property_tree::ptree, which can be used to parse the fields of the object.
Retail answered 23/1, 2011 at 18:48 Comment(1)
Thank you bavaza... your answer explained a better approach... I liked it. Thank youJohnathanjohnathon
A
0

You should have the prior knowledge on the input property file.

Boost property tree is not a general document parser. It will do parsing and give access to the data, but must locate it manually.

I don't know there are method to navigate whole document, but if you only need the properties of your own file you can do it with very simple code.

From the boost documentation:

1) The throwing version (get):

ptree pt;
/* ... */
float v = pt.get<float>("a.path.to.float.value");

2) The default-value version (get):

ptree pt;
/* ... */
float v = pt.get("a.path.to.float.value", -1.f);

3) The optional version (get_optional):

ptree pt;
/* ... */
boost::optional<float> v = pt.get_optional<float>("a.path.to.float.value");
Admissible answered 4/1, 2011 at 20:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.