json - 提升属性树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"));
现场演示
Live On 编译器资源管理器
#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 Property Tree 来接近:
#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}
推荐阅读
- python-3.x - Keras 导入 - ModuleNotFoundError:没有名为“错误”的模块
- c# - 使用来自外部文件的数据进行 xUnit 测试
- java - 如何通过 Maven 将 jar 文件添加到 war 文件的 WEB-INF/lib 文件夹?
- python - 使用 keras 保存的 ML.NET 加载模型
- spring-boot - 在spring-boot中bean初始化之前设置系统属性
- python - 在组小部件中添加两个水平对齐的单选按钮
- ruby-on-rails - 如何使用数组创建复选框
- python - 将时间序列数据集转换为监督学习数据集
- java - javafx 3d第一人称相机透视形状
- java - 使用 Spring WebFlux 的 webclient 在 Mono 上进行有条件的重复或重试