【问题标题】:boost::ptree find? or how to access deep arrays? C++boost::ptree 找到?或者如何访问深度数组? C++
【发布时间】:2015-07-18 07:12:14
【问题描述】:

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

我有一个经常被封装的 json 文件:(pseudo-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());

错误:从 'boost::property_tree::basic_ptree, std::basic_string >::assoc_iterator' 到非标量类型 'boost::property_tree::basic_ptree, std::basic_string >::const_iterator' 请求 ptree::const_iterator myIT = jsonPT.find("FooBarValue1");

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

【问题讨论】:

  • 你能让 JSON 更合理吗?实在是太崩溃了,什么都说不出来
  • 您可以在此处查看路径算法以获得灵感stackoverflow.com/a/29199812/85371(处理与 JSON 相同,因为它只适用于 ptree)
  • 编辑没有使 json 有效(甚至没有关闭)。我已经为您完成了,请参阅我的答案:/

标签: json c++11 boost ptree


【解决方案1】:

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

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"
                    }]
                }]
            }]
        }]
    }
}

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);
}

【讨论】:

  • 哇! thx 看起来真的很棒很神奇!我会尝试将其集成到我的程序中!
  • 感谢清理损坏的 JSON,我也忘了告诉每个 FooBarDeep 都是一个 FooBarDeepName 那么这样我就可以从一个键中获取所有数据,是否还有一个很好的选择来获取它们键中的值?我所有的 FooBarDeep 都是 FooBarDeep 并且我有 (n) 个,只有 FooBarDeepName = "alwaysdifferent" 现在我需要读取 FooBarDeepName 并且如果它的 "NameOfFoo_I_want" 将下面的东西写在向量或类似的东西中。我想我得问问给我发这个 JSON 的人,为什么它会这么愚蠢。
  • @Druide 请。只是发布一个新问题?带有 7 行演示 JSON。评论不能以这种方式工作,您不能通过更改问题来真正使现有答案无效。如果您将其发布为更清晰的问题,我会看看。
【解决方案2】:

find() 用于按键检索子节点;它不会搜索整个 ptree。它返回一个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。

【讨论】:

  • 谢谢!希望有一个选项可以不递归地执行此操作。我现在就这样做,并希望得到正确的。如果我做一个 node.find("FooBarValue1");我得到所有 FooBarValue1 到 mlat。我怎么知道它是来自 FooBarDeepDeep1 还是 2 还是 3?
  • @Druide 您可以在执行递归搜索时记录到达特定节点所采用的路径。
  • @ecatumur 我在 c++11 中需要它,目前我没有在我的函数中转换自动录制功能......不知道也许我需要让我的周末头脑清醒...此刻我感觉我什么都不懂了:/
  • @Druide 改为经典仿函数方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-07-02
  • 1970-01-01
  • 2018-01-11
  • 1970-01-01
  • 2013-04-15
  • 2021-12-31
  • 2017-12-28
相关资源
最近更新 更多