我无法提升C++property_tree将嵌套密钥解析为 JSON 字符串



使用JSON字符串,我能够从JSON中获得键的值,而无需任何嵌套键:

std::string getFieldFromJson(std::string json, std::string field)
{
std::stringstream jsonEncoded(json); // string to stream
boost::property_tree::ptree root;
boost::property_tree::read_json(jsonEncoded, root);

if (root.empty())
return "";

return root.get <std::string>(field);
}

但是如果我有这样的JSON,我就不能这样做了:

{
"user": {
"id": 1,
"created_at": "2017-08-16T09:23:48.525+02:00",
......
}

例如,我想读取键"created_at"的值。

使用Boost JSON:

Live On Coliru

#include <boost/algorithm/string.hpp>
#include <boost/json.hpp>
#include <boost/json/src.hpp> // for header-only/COLIRU
#include <iostream>
namespace json = boost::json;
static std::string getFieldFromJson(std::string_view json,
std::string_view field) {
std::vector<std::string_view> tokens;
boost::algorithm::split(tokens, field, boost::algorithm::is_any_of("."));
auto el = boost::json::parse({json.data(), json.size()});
for (std::string_view token : tokens)
el = el.at({token.data(), token.size()});
return value_to<std::string>(el);
}
int main() {
auto input = R"(
{
"user": {
"id": 1,
"created_at": "2017-08-16T09:23:48.525+02:00",
"name": "John Doe"
}
})";
std::cout << getFieldFromJson(input, "user.created_at") << std::endl;
}

如果有任何错误/没有找到,它抛出一个异常

改进界面

与其每次解析,不如解析一次:

Live On Coliru

#include <boost/algorithm/string.hpp>
#include <boost/json.hpp>
#include <boost/json/src.hpp> // for header-only/COLIRU
#include <iostream>
namespace json = boost::json;
static json::value const& property(json::value const& root,
std::string_view   expr) {
std::vector<std::string_view> tokens;
boost::algorithm::split(tokens, expr, boost::algorithm::is_any_of("."));
auto* cursor = &root;
for (std::string_view token : tokens)
cursor = &(cursor->at({token.data(), token.size()}));
return *cursor;
}
int main() {
auto doc = json::parse(R"( {
"user": {
"id": 1,
"created_at": "2017-08-16T09:23:48.525+02:00",
"name": "John Doe"
}
})");
std::cout << property(doc, "user.created_at") << std::endl;
}

打印

"2017-08-16T09:23:48.525+02:00"

更好:映射你的类型

如果你处理丢失的数据,你可以创建映射器,这样你就不必一直手动强制数据类型:

Live On Coliru

#include <boost/algorithm/string.hpp>
#include <boost/date_time/local_time/local_time_io.hpp>
#include <boost/date_time/local_time/conversion.hpp>
#include <boost/json.hpp>
#include <boost/json/src.hpp> // for header-only/COLIRU
#include <iostream>
namespace json = boost::json;
using boost::local_time::local_date_time;
boost::local_time::time_zone_ptr
tz(new boost::local_time::posix_time_zone("MST-07:00:00"));
namespace boost::local_time {
static local_date_time tag_invoke(json::value_to_tag<local_date_time>, json::value const& v) {
std::stringstream iss;
iss.exceptions(std::ios::failbit | std::ios::badbit);
{
auto& s = v.as_string();
std::cout << "Trying: " << s << std::endl;
iss.write(s.data(), s.size());
}
local_date_time ldt(boost::date_time::not_a_date_time, tz);
iss.imbue(std::locale(
iss.getloc(), new local_time_input_facet("%Y-%m-%dT%H:%M:%S%Q")));
iss >> ldt;
return ldt;
}
}
struct User {
int64_t         id;
local_date_time createdAt;
std::string     name;
friend User tag_invoke(json::value_to_tag<User>, json::value const& v) {
auto& user = v.at("user");
std::cout << user << std::endl;
return {
user.at("id").as_int64(),
value_to<local_date_time>(user.at("created_at")),
value_to<std::string>(user.at("name")),
};
}
};
using Users = std::vector<User>;
int main() {
auto doc = json::parse(R"(
[
{
"user": {
"id": 1,
"created_at": "2017-08-16T09:23:48.525+02:00",
"name": "John Doe"
}
},
{
"user": {
"id": 2,
"created_at": "2022-04-23T14:56:16+00:00",
"name": "Jane Doe"
}
}
]
)");
auto users = value_to<Users>(doc);
auto now   = boost::local_time::local_sec_clock::local_time(tz);
for (auto& [id, createdAt, name] : users) {
std::cout << "user #" << id << " " << std::quoted(name)
<< " was created " << (now - createdAt).total_seconds()
<< " seconds agon";
}
}

打印。

{"id":1,"created_at":"2017-08-16T09:23:48.525+02:00","name":"John Doe"}
Trying: "2017-08-16T09:23:48.525+02:00"
{"id":2,"created_at":"2022-04-23T14:56:16+00:00","name":"Jane Doe"}
Trying: "2022-04-23T14:56:16+00:00"
user #1 "John Doe" was created 147853388 seconds ago
user #2 "Jane Doe" was created 3040 seconds ago

谢谢。我还用next:

解决了这个问题。
std::string getFieldFromJson(std::string json, std::string field)
{
std::stringstream jsonEncoded(json); // string to stream convertion
boost::property_tree::ptree root;
boost::property_tree::read_json(jsonEncoded, root);
return (root.get<std::string>("user." + field));
}

最新更新