提升 属性 树 json

boost property tree json

我有一个 JSON 文件:

{
   "level_1" :
   {
      "level_1_1" : [[1, "text", 0, 1, 2],
                     [2, "text", 1, 3, 4],
                     [3, "text", 5, 6, 8],
                     [7, "text", 5, 4, 3]
                    ],
      "level_1_2" : [[....]],
      "level_1_3" : [[....]]
   }
}

我要获取内容get_child(level_1.level_1_1) 并将其放入 std::map<int, struct json_data>,其中

struct json_data {
   std::string str;
   int num1, num2, num3;
};

我该怎么做?

请不要将 属性 树当作 JSON 库来使用。

在 boost 1.75 中你可以使用 Boost Json:

提升Json

Boost Json 允许您使用 value_to<T> 进行自动转换。使用 tag_invoke:

为您自己的类型扩展它
struct json_data {
   std::string str;
   int64_t num1, num2, num3;

   //for json input
   friend json_data tag_invoke(json::value_to_tag<json_data>, json::value const& v) {
       auto& arr = v.as_array();
       return {
           value_to<std::string>(arr[1]),
           //std::string(s.data(), s.size()),
           arr[2].as_int64(),
           arr[3].as_int64(),
           arr[4].as_int64()
       };
   }
};

现在您可以“直接”阅读它:

auto doc = json::parse(json_text);

using SubLevel = std::vector<json_data>;
using Level    = std::map<std::string, SubLevel>;
auto level_1   = json::value_to<Level>(doc.as_object()["level_1"]);

它很管用。您可以更进一步并解析整个文件:

using File = std::map<std::string, Level>;
auto all   = json::value_to<File>(doc);
fmt::print("Whole file: {}\n", fmt::join(all, "\n"));

现场演示

在编译器资源管理器上运行

#include <boost/json.hpp>
#include <boost/json/src.hpp> // for header only
#include <iostream>
#include <iomanip>
#include <fmt/ranges.h>
#include <fmt/ostream.h>
namespace json = boost::json;

struct json_data {
std::string str;
int64_t num1, num2, num3;

//for json input
friend json_data tag_invoke(json::value_to_tag<json_data>, json::value const& v) {
    auto& arr = v.as_array();
    return {
        value_to<std::string>(arr[1]),
        //std::string(s.data(), s.size()),
        arr[2].as_int64(),
        arr[3].as_int64(),
        arr[4].as_int64()
    };
}

//for debug output
friend std::ostream& operator<<(std::ostream& os, json_data const& jd) {
    return os << '{' << std::quoted(jd.str) << ';' << jd.num1 << ';'
                << jd.num2 << ';' << jd.num3 << '}';
}
};

extern std::string const json_text;

int main() {
    auto doc = json::parse(json_text);

    using SubLevel = std::vector<json_data>;
    using Level    = std::map<std::string, SubLevel>;
    auto level_1   = json::value_to<Level>(doc.as_object()["level_1"]);

    fmt::print("Level 1: {}\n", fmt::join(level_1, "\n\t - "));

    using File = std::map<std::string, Level>;
    auto all   = json::value_to<File>(doc);
    fmt::print("Whole file: {}\n", all);
}

std::string const json_text = R"(
{
    "level_1": {
        "level_1_1": [
            [1, "text", 0, 1, 2],
            [2, "text", 1, 3, 4],
            [3, "text", 5, 6, 8],
            [7, "text", 5, 4, 3]],
        "level_1_2": [
            [9, "text", 8, 9, 10],
            [10, "text", 9, 11, 12],
            [11, "text", 13, 14, 16],
            [15, "text", 13, 12, 11]],
        "level_1_3": [
            [17, "text", 16, 17, 18],
            [18, "text", 17, 19, 20],
            [19, "text", 21, 22, 24],
            [23, "text", 21, 20, 19]]
    }
})";

版画

Level 1: ("level_1_1", {{"text";0;1;2}, {"text";1;3;4}, {"text";5;6;8}, {"text";5;4;3}})
         - ("level_1_2", {{"text";8;9;10}, {"text";9;11;12}, {"text";13;14;16}, {"text";13;12;
11}})
         - ("level_1_3", {{"text";16;17;18}, {"text";17;19;20}, {"text";21;22;24}, {"text";21;
20;19}})

Whole file: ("level_1", {("level_1_1", {{"text";0;1;2}, {"text";1;3;4}, {"text";5;6;8}, {"text
";5;4;3}}), ("level_1_2", {{"text";8;9;10}, {"text";9;11;12}, {"text";13;14;16}, {"text";13;12
;11}}), ("level_1_3", {{"text";16;17;18}, {"text";17;19;20}, {"text";21;22;24}, {"text";21;20;
19}})})

提升属性树

如果必须,可以尝试使用 Boost 接近 属性 树:

Live On Coliru

#define BOOST_BIND_GLOBAL_PLACEHOLDERS 
#include <boost/property_tree/json_parser.hpp>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <fmt/ranges.h>
#include <fmt/ostream.h>

using boost::property_tree::ptree;

struct json_data {
std::string str;
int num1, num2, num3;

friend void read_tree(ptree const& pt, std::vector<json_data>& into) {
    auto r = pt.equal_range("");
    for (;r.first != r.second; ++r.first) {
        read_tree(r.first->second, into.emplace_back());
    }
}

friend void read_tree(ptree const& pt, json_data& into) {
    auto r = pt.equal_range("");
    assert(std::distance(r.first, r.second) == 5);

    auto it = r.first;
    into = {
        (++it)->second.get_value<std::string>(),
        //std::string(s.data(), s.size()),
        (++it)->second.get_value<int>(),
        (++it)->second.get_value<int>(),
        (++it)->second.get_value<int>()
    };
}

//for debug output
friend std::ostream& operator<<(std::ostream& os, json_data const& jd) {
    return os << '{' << std::quoted(jd.str) << ';' << jd.num1 << ';'
                << jd.num2 << ';' << jd.num3 << '}';
}
};

extern std::string const json_text;

int main() {
    ptree pt;
    {
        std::istringstream iss(json_text);
        read_json(iss, pt);
    }

    std::vector<json_data> level_1;
    read_tree(pt.get_child("level_1.level_1_2"), level_1);
    fmt::print("level_1: {}\n", fmt::join(level_1, "\n\t - "));
}

std::string const json_text = R"(
{
    "level_1": {
        "level_1_1": [
            [1, "text", 0, 1, 2],
            [2, "text", 1, 3, 4],
            [3, "text", 5, 6, 8],
            [7, "text", 5, 4, 3]],
        "level_1_2": [
            [9, "text", 8, 9, 10],
            [10, "text", 9, 11, 12],
            [11, "text", 13, 14, 16],
            [15, "text", 13, 12, 11]],
        "level_1_3": [
            [17, "text", 16, 17, 18],
            [18, "text", 17, 19, 20],
            [19, "text", 21, 22, 24],
            [23, "text", 21, 20, 19]]
    }
})";

版画

level_1: {"text";8;9;10}
         - {"text";9;11;12}
         - {"text";13;14;16}
         - {"text";13;12;11}

版画

Level 1:
     - {"text";8;9;10}
     - {"text";9;11;12}
     - {"text";13;14;16}
     - {"text";13;12;11}