boost::ptree 找到了吗?或者如何访问深层数组?C++

Dru*_*ide 3 json boost boost-propertytree c++11

我现在已经尝试了太多时间来从 boost 库访问 json_reader ptree。

\n\n

我有一个经常封装的 json 文件:(pseudo-json:)

\n\n
"Foo": {\n  "nameofFoo:"foofoo"\n  "Bar": [{\n    "BarFoo": \n      { BarFooDeep: { \n           BarFooDeepDeep: { \n            "BarFooValue1": 123 \n            "BarFooValue2" : 456\n          }\n        }\n      }\n     "FooBar": [ {\n        "FooBarDeep" :[ {\n           FooBarDeepDeep:[ {\n              FooBarValue1: "ineedthis"\n              FooBarValue2: "andthis"\n              } ]\n           FooBarDeepDeep1:[ {\n              FooBarValue1: "ineedthis"\n              FooBarValue2: "andthis"\n              } ]\n        "FooBarDeep" :[ {\n           FooBarDeepDeep2:[ {\n              FooBarValue1: "ineedthis"\n              FooBarValue2: "andthis"\n              } ]\n           FooBarDeepDeep3:[ {\n              FooBarValue1: "ineedthis"\n              FooBarValue2: "andthis"\n              } ]\nand so on .... won t complete this now...\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在我只需要获取所有FooBar的FooBarValue1和FooBarValue2。

\n\n

我知道 ptree 将数组与空子元素 ("") 放在一起

\n\n

我可以通过递归迭代所有子项来访问所有成员。

\n\n

但是有没有更好的方法来访问特殊值呢?

\n\n

ptree如何找到作品?我总是遇到编译器错误...

\n\n
ptree jsonPT;\nread_json( JSON_PATH, jsonPT);\nptree::const_iterator myIT = jsonPT.find("FooBarValue1");\ndouble mlat = boost::lexical_cast<int>(myIT->second.data());\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

错误: 从\n \xe2\x80\x98boost::property_tree::basic_ptree,\n std::basic_string >::assoc_iterator\xe2\x80\x99 转换为非标量类型\n \xe2\x80\x98boost:: property_tree::basic_ptree,\n std::basic_string >::const_iterator\xe2\x80\x99 请求\n ptree::const_iterator myIT = jsonPT.find("FooBarValue1");

\n
\n\n

谁能给我一个有用的提示如何访问这个 ptree?!?

\n

seh*_*ehe 5

正如我评论的链接答案(Boost.PropertyTree subpathprocessing)中所暗示的,您可以编写自己的“选择器”查询,这样您就可以编写如下内容:

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);
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

作为简单的工作演示打印:

Specific children but in arrays: andthis6, 
Single wildcard: andthis6, andthis7, andthis8, andthis9, 
Two wildcards: andthis1, andthis2, andthis3, andthis4, andthis6, andthis7, andthis8, andthis9, 
Run Code Online (Sandbox Code Playgroud)

即使用以下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"
                    }]
                }]
            }]
        }]
    }
}
Run Code Online (Sandbox Code Playgroud)

Live On Coliru

完整列表

Live On Coliru

#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);
}
Run Code Online (Sandbox Code Playgroud)