Я не могу с помощью C++ повысить свойство_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. Используйте специальную библиотеку, например JSON для современного C++.

Ted Lyngmo 23.04.2022 12:45

поддержка JSON дерева свойств предназначена только для чтения и записи деревьев свойств, она не предназначена и не может быть парсером JSON общего назначения.

Alan Birtles 23.04.2022 13:03

Это не личное мнение, @TedLyngmo. Это одна из самых серьезных проблем с Boost: все злоупотребляют деревом свойств за то, для чего оно никогда не подходило.

sehe 23.04.2022 16:26
3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
1
3
33
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Использование Boost JSON:

Жить на Колиру

#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;
}

Выдает исключение, если что-то пойдет не так/не будет найдено

Улучшить интерфейс

Вместо того, чтобы анализировать каждый раз, вы, вероятно, проанализируете один раз:

Жить на Колиру

#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"

Еще лучше: сопоставьте свои типы

Если вы работаете с потерянными данными, вы можете создать преобразователи, чтобы вам не приходилось все время вручную принуждать типы данных:

Жить на Колиру

#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 ago\n";
    }
}

Отпечатки, например.

{"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

Спасибо. Я также решил это следующим образом:

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));
}

Другие вопросы по теме