How return leaf nodes of a boost::property_tree

空扰寡人 提交于 2020-01-02 09:19:09

问题


I have a property tree where all the data is stored in its leaf nodes. The Tree, however, has a complex structure. What I want to do now is:

  1. get all (and only the) leaf nodes of the tree, for they contain the data and
  2. recall the path leading to the respective leaf node

Eventually, I want to receive a key/value pair of all (and only the) leaf nodes where the key contains the complete path to the node and the value contains the node's value.

My questions are:

  1. Is there a more convenient way than to recursively iterate through the whole tree, store the respective path and read out the values of the nodes that don't have children (i.e. a "get_leaves()" function)?
  2. If I have some pointer to a subtree (ptree variable, iterator, whatever..) of a given tree, is there a method to easily determine the relative path of that subtree inside the tree?

回答1:


I'd just write some helper functions. They're really not that difficult. Here's a completely generic tree visitation function that optionally takes a predicate:

template <typename Tree, typename F, typename Pred/* = bool(*)(Tree const&)*/, typename PathType = std::string>
void visit_if(Tree& tree, F const& f, Pred const& p, PathType const& path = PathType())
{
    if (p(tree))
        f(path, tree);

    for(auto& child : tree)
        if (path.empty())
            visit_if(child.second, f, p, child.first);
        else
            visit_if(child.second, f, p, path + "." + child.first);
}

template <typename Tree, typename F, typename PathType = std::string>
void visit(Tree& tree, F const& f, PathType const& path = PathType())
{
    visit_if(tree, f, [](Tree const&){ return true; }, path);
}

You can use it with a predicate like

#include <boost/property_tree/ptree.hpp>

bool is_leaf(boost::property_tree::ptree const& pt) {
    return pt.empty();
}

And here's a simple demo:

Live On Coliru

#include <iostream>
int main()
{
    using boost::property_tree::ptree;
    auto process = [](ptree::path_type const& path, ptree const& node) {
            std::cout << "leave node at '" << path.dump() << "' has value '" << node.get_value("") << "'\n";
        };

    ptree pt;
    pt.put("some.deeply.nested.values", "just");
    pt.put("for.the.sake.of.demonstration", 42);

    visit_if(pt, process, is_leaf);
}

Prints:

leave node at 'some.deeply.nested.values' has value 'just'
leave node at 'for.the.sake.of.demonstration' has value '42'

UPDATE

Just noted the second half of the question. here's how to do it using the same visitor:

template <typename Tree>
boost::optional<std::string> path_of_optional(Tree const& tree, Tree const& target) {
    boost::optional<std::string> result;

    visit(tree, [&](std::string const& path, Tree const& current) { if (&target == &current) result = path; });

    return result;
}

template <typename Tree>
std::string path_of(Tree const& tree, Tree const& target) {
    auto r = path_of_optional(tree, target);
    if (!r) throw std::range_error("path_of");
    return *r;
}

And a demo Live On Coliru

std::cout << "Path from node: " << path_of(pt, pt.get_child("for.the.sake")) << "\n";


来源:https://stackoverflow.com/questions/30571536/how-return-leaf-nodes-of-a-boostproperty-tree

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!