return 如何 boost::property_tree 的叶节点
How return leaf nodes of a boost::property_tree
我有一棵 属性 树,所有数据都存储在它的叶节点中。然而,树具有复杂的结构。我现在要做的是:
- 获取树的所有(且仅)叶节点,因为它们包含数据并且
- 回想一下通往各自叶节点的路径
最终,我想接收一对 key/value 所有(且仅)叶节点,其中键包含节点的完整路径,值包含节点的值。
我的问题是:
- 有没有比递归遍历整棵树更方便的方法,存储各自的路径并读出没有children的节点的值(即“get_leaves()”函数)?
- 如果我有一些指向给定树的子树(ptree 变量,迭代器,随便什么..)的指针,是否存在一种轻松确定该子树在树内的相对路径的方法?
我只是写了一些辅助函数。他们真的没有那么难。这是一个完全通用的树访问函数,可以选择性地使用谓词:
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);
}
您可以将它与谓词一起使用,例如
#include <boost/property_tree/ptree.hpp>
bool is_leaf(boost::property_tree::ptree const& pt) {
return pt.empty();
}
这是一个简单的演示:
#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);
}
打印:
leave node at 'some.deeply.nested.values' has value 'just'
leave node at 'for.the.sake.of.demonstration' has value '42'
更新
刚刚注意到问题的后半部分。以下是使用同一个访客的方法:
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 == ¤t) 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;
}
还有一个演示 Live On Coliru
std::cout << "Path from node: " << path_of(pt, pt.get_child("for.the.sake")) << "\n";
我有一棵 属性 树,所有数据都存储在它的叶节点中。然而,树具有复杂的结构。我现在要做的是:
- 获取树的所有(且仅)叶节点,因为它们包含数据并且
- 回想一下通往各自叶节点的路径
最终,我想接收一对 key/value 所有(且仅)叶节点,其中键包含节点的完整路径,值包含节点的值。
我的问题是:
- 有没有比递归遍历整棵树更方便的方法,存储各自的路径并读出没有children的节点的值(即“get_leaves()”函数)?
- 如果我有一些指向给定树的子树(ptree 变量,迭代器,随便什么..)的指针,是否存在一种轻松确定该子树在树内的相对路径的方法?
我只是写了一些辅助函数。他们真的没有那么难。这是一个完全通用的树访问函数,可以选择性地使用谓词:
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);
}
您可以将它与谓词一起使用,例如
#include <boost/property_tree/ptree.hpp>
bool is_leaf(boost::property_tree::ptree const& pt) {
return pt.empty();
}
这是一个简单的演示:
#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);
}
打印:
leave node at 'some.deeply.nested.values' has value 'just'
leave node at 'for.the.sake.of.demonstration' has value '42'
更新
刚刚注意到问题的后半部分。以下是使用同一个访客的方法:
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 == ¤t) 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;
}
还有一个演示 Live On Coliru
std::cout << "Path from node: " << path_of(pt, pt.get_child("for.the.sake")) << "\n";