简体   繁体   English

如何返回boost :: property_tree的叶节点

[英]How return leaf nodes of a boost::property_tree

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 (ie a " get_leaves() " function)? 除了递归遍历整棵树,存储各自的路径并读出没有子节点的值(即“ get_leaves()函数”)之外,还有没有更方便的方法?
  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? 如果我有指向给定树的子树的指针( ptree变量, 迭代器等),是否有一种方法可以轻松确定树内该子树的相对路径?

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 生活在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 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 和演示Live On Coliru

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM