【问题标题】:boost property tree json提升属性树json
【发布时间】:2021-04-14 06:10:39
【问题描述】:

我有一个 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 boost-propertytree


    【解决方案1】:

    请不要像使用 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, 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 属性树

    如果必须,可以尝试使用 Boost Property Tree 接近:

    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}
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-02
    • 1970-01-01
    • 1970-01-01
    • 2016-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多