6

I'm using boots's property_tree library. I'm looking for a way to get a child node from a ptree object, but return an empty ptree if failed. I came across a nice example in property_tree/examples/empty_ptree_trick.cpp:

void process_settings(const std::string &filename)
{
    ptree pt;
    read_info(filename, pt);    
    const ptree &settings = pt.get_child("settings", empty_ptree<ptree>());
    std::cout << "\n    Processing " << filename << std::endl;
    std::cout << "        Setting 1 is " << settings.get("setting1", 0) << std::endl;
    std::cout << "        Setting 2 is " << settings.get("setting2", 0.0) << std::endl;
    std::cout << "        Setting 3 is " << settings.get("setting3", "default") <<     std::endl;
}

which does exactly what I need. The problem is that the compiler complains that empty_ptree() function is not a member of boost:property_tree. Any ideas where empty_ptree() is?

I'm using boost 1.44 on VS2010.

bavaza
  • 10,319
  • 10
  • 64
  • 103

2 Answers2

2

I have just blown a full day trying to answer that question!

This was my solution. Firstly I used pointers, and not references as you have to initialize them immediately. Then I just caught the exception and added a new ptree.

using namespace boost::property_tree;

ptree r_pt;
ptree *c_pt;

read_xml( "file.xml" , r_pt);

try {
    c_pt = &(r_pt.get_child( "example" ));
}
catch (ptree_bad_path) {
    c_pt = &(r_pt.put_child( "example", ptree() ));
}

std::cout << "Setting 1 is " << c_pt.get("setting1", 0) << std::endl;

From what I could pick up they expect us to use the boost::optional type. But I'm just a beginner..

EDIT I just found the implementation of empty_ptree<>.

template<class Ptree>
    inline const Ptree &empty_ptree()
    {
        static Ptree pt;
        return pt;
    }

I think you can just add this to your code and use it as described in the empty_ptree_trick.cpp, but I am sticking with my solution for now untill I find out how its actually supposed to be done.

expelledboy
  • 2,033
  • 18
  • 18
  • @expelleboy - thanks for the effort :-). There are, however, a few issues with your suggested code: 1) `read_xml` can also throw - so you may want to put it in the `try` block. 2) I'm not sure what is the lifespan of the ptree returned by `get_child`, however, the examples in boost always assign the result from get<>, and never take their address. You might end up with a dangling pointer. 3) you can skip the `try-catch`, as the optional version of get<> (the one used in your catch block), never throws. 4) It is more efficient to return a reference to the empty_ptree than to create it. – bavaza Mar 06 '11 at 09:25
  • @bavaza np. Actually I had dealt with these issues was by creating a class (xml_branch in my code) that I inherited that forces me to create instances only within a class that inherits xml_branch, or a pointer to a ptree. The root class then has the actual ptree and its pointer. Then root handles all exceptions raised upon initialization of the member xml_branch's. Unfortunately I cant show you the full source, but I can say it a rather elegant way of doing it. – expelledboy Mar 07 '11 at 10:44
  • Sorry I meant to say "the branch handles all exceptions rais...", but I cant seem to edit my comment.. – expelledboy Mar 07 '11 at 11:07
  • I am also very curious where the empty_ptree in http://www.boost.org/doc/libs/1_55_0/libs/property_tree/examples/empty_ptree_trick.cpp comes from! – Ela782 Dec 06 '13 at 18:38
  • OK, @expelledboy, you found the implementation -- *but in which file*? When I `grep 'empty_ptree' -r` in my `$BOOST_ROOT` there are 11 hits -- most are comments or documentation, none are the actual implementation. – Christian Severin Jul 12 '17 at 10:12
1
void process_settings(const std::string &filename)
{
    ptree pt;
    read_info(filename, pt);    
    const ptree &settings = pt.get_child("settings", ptree());
    std::cout << "\n    Processing " << filename << std::endl;
    std::cout << "        Setting 1 is " << settings.get("setting1", 0) << std::endl;
    std::cout << "        Setting 2 is " << settings.get("setting2", 0.0) << std::endl;
    std::cout << "        Setting 3 is " << settings.get("setting3", "default") <<     std::endl;
}

Note, that will prevent throwing an instance of 'boost::wrapexceptboost::property_tree::ptree_bad_path'

Edward Kigwana
  • 324
  • 2
  • 9