提升属性树json 提升 Json现场演示

问题描述

我有一个 JSON 文件

{
   "level_1" :
   {
      "level_1_1" : [[1,"text",1,2],[2,3,4],[3,5,6,8],[7,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"));

现场演示

Live On Compiler Explorer

#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,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]),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",1,2],[2,3,4],[3,5,6,8],[7,4,3]],"level_1_2": [
            [9,8,9,10],[10,11,12],[11,13,14,16],[15,12,11]],"level_1_3": [
            [17,16,17,18],[18,19,20],[19,21,22,24],[23,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
";5;4;3}}),("level_1_2",{"text";13;12
;11}}),("level_1_3",{"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,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>(),(++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","\n\t - "));
}

std::string const json_text = R"(
{
    "level_1": {
        "level_1_1": [
            [1,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}