boost::ptree找到了吗?或者如何访问深层数组? C++
boost::ptree find? or how to access deep arrays? C++
我已经尝试了太多时间,无法从 boost 库访问 json_reader ptree。
我有一个json文件,经常被封装:(伪json:)
"Foo": {
"nameofFoo:"foofoo"
"Bar": [{
"BarFoo":
{ BarFooDeep: {
BarFooDeepDeep: {
"BarFooValue1": 123
"BarFooValue2" : 456
}
}
}
"FooBar": [ {
"FooBarDeep" :[ {
FooBarDeepDeep:[ {
FooBarValue1: "ineedthis"
FooBarValue2: "andthis"
} ]
FooBarDeepDeep1:[ {
FooBarValue1: "ineedthis"
FooBarValue2: "andthis"
} ]
"FooBarDeep" :[ {
FooBarDeepDeep2:[ {
FooBarValue1: "ineedthis"
FooBarValue2: "andthis"
} ]
FooBarDeepDeep3:[ {
FooBarValue1: "ineedthis"
FooBarValue2: "andthis"
} ]
and so on .... won t complete this now...
现在只需要获取所有FooBar的FooBarValue1和FooBarValue2即可
我知道 ptree 将数组与空子元素 ("") 放在一起
我可以通过递归遍历所有子项来访问所有成员。
但是没有更好的方法来访问特殊值吗?
ptree find 是如何工作的?我总是遇到编译器错误...
ptree jsonPT;
read_json( JSON_PATH, jsonPT);
ptree::const_iterator myIT = jsonPT.find("FooBarValue1");
double mlat = boost::lexical_cast<int>(myIT->second.data());
error: conversion from
‘boost::property_tree::basic_ptree,
std::basic_string >::assoc_iterator’ to non-scalar type
‘boost::property_tree::basic_ptree,
std::basic_string >::const_iterator’ requested
ptree::const_iterator myIT = jsonPT.find("FooBarValue1");
谁能给我一个有用的提示,告诉我如何访问此 ptree?!?
find()
用于按键检索子节点;它不会搜索整个 ptree。它 returns 一个 assoc_iterator
(或 const_assoc_iterator
),您可以通过父级上的 to_iterator()
方法将其转换为 iterator
:
ptree::const_assoc_iterator assoc = jsonPT.find("FooBarValue1");
ptree::const_iterator myIT = jsonPT.to_iterator(assoc);
要搜索 ptree,您需要递归地迭代它:
struct Searcher {
struct Path { std::string const& key; Path const* prev; };
void operator()(ptree const& node, Path const* path = nullptr) const {
auto it = node.find("FooBarValue1");
if (it == node.not_found()) {
for (auto const& child : node) { // depth-first search
Path next{child.first, path};
(*this)(child.second, &next);
}
} else { // found "FooBarValue1"
double mlat = boost::lexical_cast<int>(myIT->second.data());
// ...
std::cout << "Mlat: " << mlat << std::endl;
std::cout << "Path (reversed): ";
for (Path const* p = path; p != nullptr; p = p->prev)
std::cout << p << ".";
std::cout << std::endl;
}
}
};
Searcher{}(jsonPT);
编写递归遍历的替代方案是 C++14 通用 lambda,或者在 C++11 中使用 std::function
.
的类型擦除具体 lambda
正如我评论的链接答案中所暗示的那样 (Boost.PropertyTree subpath processing),您可以编写自己的 "selector" 查询,这样您就可以编写如下内容:
read_json("input.txt", pt);
std::ostream_iterator<std::string> out(std::cout, ", ");
std::cout << "\nSpecific children but in arrays: ";
enumerate_path(pt, "Foo.Bar..FooBar..FooBarDeep1..FooBarDeepDeep6..FooBarValue2", out);
std::cout << "\nSingle wildcard: ";
enumerate_path(pt, "Foo.Bar..FooBar..FooBarDeep1..*..FooBarValue2", out);
std::cout << "\nTwo wildcards: ";
enumerate_path(pt, "Foo.Bar..FooBar..*..*..FooBarValue2", out);
enumerate_path
函数不需要太复杂,它可以接受任何输出迭代器(所以你也可以 back_inserter(some_vector)
):
template <typename Tree, typename Out, typename T = std::string>
Out enumerate_path(Tree const& pt, typename Tree::path_type path, Out out) {
if (path.empty())
return out;
if (path.single()) {
*out++ = pt.template get<T>(path);
} else {
auto head = path.reduce();
for (auto& child : pt) {
if (head == "*" || child.first == head) {
out = enumerate_path(child.second, path, out);
}
}
}
return out;
}
作为简单的工作演示打印:
Specific children but in arrays: andthis6,
Single wildcard: andthis6, andthis7, andthis8, andthis9,
Two wildcards: andthis1, andthis2, andthis3, andthis4, andthis6, andthis7, andthis8, andthis9,
也就是跟下面input.txt:
{
"Foo": {
"nameofFoo": "foofoo",
"Bar": [{
"BarFoo": {
"BarFooDeep": {
"BarFooDeepDeep": {
"BarFooValue1": 123,
"BarFooValue2": 456
}
}
},
"FooBar": [{
"FooBarDeep0": [{
"FooBarDeepDeep1": [{
"FooBarValue1": "ineedthis1",
"FooBarValue2": "andthis1"
}],
"FooBarDeepDeep2": [{
"FooBarValue1": "ineedthis2",
"FooBarValue2": "andthis2"
}]
},
{
"FooBarDeepDeep3": [{
"FooBarValue1": "ineedthis3",
"FooBarValue2": "andthis3"
}],
"FooBarDeepDeep4": [{
"FooBarValue1": "ineedthis4",
"FooBarValue2": "andthis4"
}]
}],
"FooBarDeep1": [{
"FooBarDeepDeep6": [{
"FooBarValue1": "ineedthis6",
"FooBarValue2": "andthis6"
}],
"FooBarDeepDeep7": [{
"FooBarValue1": "ineedthis7",
"FooBarValue2": "andthis7"
}]
},
{
"FooBarDeepDeep8": [{
"FooBarValue1": "ineedthis8",
"FooBarValue2": "andthis8"
}],
"FooBarDeepDeep9": [{
"FooBarValue1": "ineedthis9",
"FooBarValue2": "andthis9"
}]
}]
}]
}]
}
}
完整列表
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <iostream>
template <typename Tree, typename Out, typename T = std::string>
Out enumerate_path(Tree const& pt, typename Tree::path_type path, Out out) {
if (path.empty())
return out;
if (path.single()) {
*out++ = pt.template get<T>(path);
} else {
auto head = path.reduce();
for (auto& child : pt) {
if (head == "*" || child.first == head) {
out = enumerate_path(child.second, path, out);
}
}
}
return out;
}
int main() {
std::ostream_iterator<std::string> out(std::cout, ", ");
using namespace boost::property_tree;
ptree pt;
read_json("input.txt", pt);
std::cout << "\nSpecific children but in arrays: ";
enumerate_path(pt, "Foo.Bar..FooBar..FooBarDeep1..FooBarDeepDeep6..FooBarValue2", out);
std::cout << "\nSingle wildcard: ";
enumerate_path(pt, "Foo.Bar..FooBar..FooBarDeep1..*..FooBarValue2", out);
std::cout << "\nTwo wildcards: ";
enumerate_path(pt, "Foo.Bar..FooBar..*..*..FooBarValue2", out);
}
我已经尝试了太多时间,无法从 boost 库访问 json_reader ptree。
我有一个json文件,经常被封装:(伪json:)
"Foo": {
"nameofFoo:"foofoo"
"Bar": [{
"BarFoo":
{ BarFooDeep: {
BarFooDeepDeep: {
"BarFooValue1": 123
"BarFooValue2" : 456
}
}
}
"FooBar": [ {
"FooBarDeep" :[ {
FooBarDeepDeep:[ {
FooBarValue1: "ineedthis"
FooBarValue2: "andthis"
} ]
FooBarDeepDeep1:[ {
FooBarValue1: "ineedthis"
FooBarValue2: "andthis"
} ]
"FooBarDeep" :[ {
FooBarDeepDeep2:[ {
FooBarValue1: "ineedthis"
FooBarValue2: "andthis"
} ]
FooBarDeepDeep3:[ {
FooBarValue1: "ineedthis"
FooBarValue2: "andthis"
} ]
and so on .... won t complete this now...
现在只需要获取所有FooBar的FooBarValue1和FooBarValue2即可
我知道 ptree 将数组与空子元素 ("") 放在一起
我可以通过递归遍历所有子项来访问所有成员。
但是没有更好的方法来访问特殊值吗?
ptree find 是如何工作的?我总是遇到编译器错误...
ptree jsonPT;
read_json( JSON_PATH, jsonPT);
ptree::const_iterator myIT = jsonPT.find("FooBarValue1");
double mlat = boost::lexical_cast<int>(myIT->second.data());
error: conversion from ‘boost::property_tree::basic_ptree, std::basic_string >::assoc_iterator’ to non-scalar type ‘boost::property_tree::basic_ptree, std::basic_string >::const_iterator’ requested ptree::const_iterator myIT = jsonPT.find("FooBarValue1");
谁能给我一个有用的提示,告诉我如何访问此 ptree?!?
find()
用于按键检索子节点;它不会搜索整个 ptree。它 returns 一个 assoc_iterator
(或 const_assoc_iterator
),您可以通过父级上的 to_iterator()
方法将其转换为 iterator
:
ptree::const_assoc_iterator assoc = jsonPT.find("FooBarValue1");
ptree::const_iterator myIT = jsonPT.to_iterator(assoc);
要搜索 ptree,您需要递归地迭代它:
struct Searcher {
struct Path { std::string const& key; Path const* prev; };
void operator()(ptree const& node, Path const* path = nullptr) const {
auto it = node.find("FooBarValue1");
if (it == node.not_found()) {
for (auto const& child : node) { // depth-first search
Path next{child.first, path};
(*this)(child.second, &next);
}
} else { // found "FooBarValue1"
double mlat = boost::lexical_cast<int>(myIT->second.data());
// ...
std::cout << "Mlat: " << mlat << std::endl;
std::cout << "Path (reversed): ";
for (Path const* p = path; p != nullptr; p = p->prev)
std::cout << p << ".";
std::cout << std::endl;
}
}
};
Searcher{}(jsonPT);
编写递归遍历的替代方案是 C++14 通用 lambda,或者在 C++11 中使用 std::function
.
正如我评论的链接答案中所暗示的那样 (Boost.PropertyTree subpath processing),您可以编写自己的 "selector" 查询,这样您就可以编写如下内容:
read_json("input.txt", pt);
std::ostream_iterator<std::string> out(std::cout, ", ");
std::cout << "\nSpecific children but in arrays: ";
enumerate_path(pt, "Foo.Bar..FooBar..FooBarDeep1..FooBarDeepDeep6..FooBarValue2", out);
std::cout << "\nSingle wildcard: ";
enumerate_path(pt, "Foo.Bar..FooBar..FooBarDeep1..*..FooBarValue2", out);
std::cout << "\nTwo wildcards: ";
enumerate_path(pt, "Foo.Bar..FooBar..*..*..FooBarValue2", out);
enumerate_path
函数不需要太复杂,它可以接受任何输出迭代器(所以你也可以 back_inserter(some_vector)
):
template <typename Tree, typename Out, typename T = std::string>
Out enumerate_path(Tree const& pt, typename Tree::path_type path, Out out) {
if (path.empty())
return out;
if (path.single()) {
*out++ = pt.template get<T>(path);
} else {
auto head = path.reduce();
for (auto& child : pt) {
if (head == "*" || child.first == head) {
out = enumerate_path(child.second, path, out);
}
}
}
return out;
}
作为简单的工作演示打印:
Specific children but in arrays: andthis6,
Single wildcard: andthis6, andthis7, andthis8, andthis9,
Two wildcards: andthis1, andthis2, andthis3, andthis4, andthis6, andthis7, andthis8, andthis9,
也就是跟下面input.txt:
{
"Foo": {
"nameofFoo": "foofoo",
"Bar": [{
"BarFoo": {
"BarFooDeep": {
"BarFooDeepDeep": {
"BarFooValue1": 123,
"BarFooValue2": 456
}
}
},
"FooBar": [{
"FooBarDeep0": [{
"FooBarDeepDeep1": [{
"FooBarValue1": "ineedthis1",
"FooBarValue2": "andthis1"
}],
"FooBarDeepDeep2": [{
"FooBarValue1": "ineedthis2",
"FooBarValue2": "andthis2"
}]
},
{
"FooBarDeepDeep3": [{
"FooBarValue1": "ineedthis3",
"FooBarValue2": "andthis3"
}],
"FooBarDeepDeep4": [{
"FooBarValue1": "ineedthis4",
"FooBarValue2": "andthis4"
}]
}],
"FooBarDeep1": [{
"FooBarDeepDeep6": [{
"FooBarValue1": "ineedthis6",
"FooBarValue2": "andthis6"
}],
"FooBarDeepDeep7": [{
"FooBarValue1": "ineedthis7",
"FooBarValue2": "andthis7"
}]
},
{
"FooBarDeepDeep8": [{
"FooBarValue1": "ineedthis8",
"FooBarValue2": "andthis8"
}],
"FooBarDeepDeep9": [{
"FooBarValue1": "ineedthis9",
"FooBarValue2": "andthis9"
}]
}]
}]
}]
}
}
完整列表
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <iostream>
template <typename Tree, typename Out, typename T = std::string>
Out enumerate_path(Tree const& pt, typename Tree::path_type path, Out out) {
if (path.empty())
return out;
if (path.single()) {
*out++ = pt.template get<T>(path);
} else {
auto head = path.reduce();
for (auto& child : pt) {
if (head == "*" || child.first == head) {
out = enumerate_path(child.second, path, out);
}
}
}
return out;
}
int main() {
std::ostream_iterator<std::string> out(std::cout, ", ");
using namespace boost::property_tree;
ptree pt;
read_json("input.txt", pt);
std::cout << "\nSpecific children but in arrays: ";
enumerate_path(pt, "Foo.Bar..FooBar..FooBarDeep1..FooBarDeepDeep6..FooBarValue2", out);
std::cout << "\nSingle wildcard: ";
enumerate_path(pt, "Foo.Bar..FooBar..FooBarDeep1..*..FooBarValue2", out);
std::cout << "\nTwo wildcards: ";
enumerate_path(pt, "Foo.Bar..FooBar..*..*..FooBarValue2", out);
}