Home > Software design >  Parse elements from json array using boost
Parse elements from json array using boost

Time:11-05

here is the json I want to parse:

{"jsonrpc":"2.0","method":"subscription","params":{"channel":"book.BTC-PERPETUAL.raw","data":{"type":"change","timestamp":1635513739435,"prev_change_id":6807100702,"instrument_name":"BTC-PERPETUAL","change_id":6807100703,"bids":[["new",60772.0,50.0], "demo"],"asks":[]}}}

and here is my code to get the values from a child:

boost::property_tree::ptree pt; boost::property_tree::read_json(ss, pt);

    std::cout << "\njsonrpc: " << pt.get<std::string>("jsonrpc") << std::endl;
    std::cout << "\nmethod: " << pt.get<std::string>("method") << std::endl;
    std::cout << "\nparams: " << pt.get<std::string>("params") << std::endl;
    std::cout << "\nparams.channel: " << pt.get<std::string>("params.channel") << std::endl;
    std::cout << "\nparams.data: " << pt.get<std::string>("params.data") << std::endl;
    std::cout << "\nparams.data.timestamp: " << pt.get<std::string>("params.data.timestamp") << std::endl;
    std::cout << "\nparams.data.instrument_name: " << pt.get<std::string>("params.data.instrument_name") << std::endl;

but when I tried to parse the array values like ("params.data.bids") it return nothing

I need help in parsing an array

CodePudding user response:

You should use a JSON Library:

Live On Compiler Explorer

#include <boost/json.hpp>
#include <boost/json/src.hpp> // header-only for Compiler Explorer
#include <iostream>
namespace json = boost::json;

int main() {
    auto req = json::parse(R"({
            "jsonrpc": "2.0",
            "method": "subscription",
            "params": {
                "channel": "book.BTC-PERPETUAL.raw",
                "data": {
                    "type": "change",
                    "timestamp": 1635513739435,
                    "prev_change_id": 6807100702,
                    "instrument_name": "BTC-PERPETUAL",
                    "change_id": 6807100703,
                    "bids": [
                        ["new", 60772.0, 50.0], "demo"],
                    "asks": []
                }
            }
        })") .as_object();

    auto& params = req["params"].as_object();
    auto& data   = params["data"].as_object();
    std::cout << "jsonrpc:                     " << req["jsonrpc"].as_string()    << "\n";
    std::cout << "methdo:                      " << req["method"].as_string()     << "\n";
    std::cout << "params.channel:              " << params["channel"].as_string() << "\n";
    std::cout << "params.data:                 " << params["data"]                << "\n";
    std::cout << "params.data.timestamp:       " << data["timestamp"]             << "\n";
    std::cout << "params.data.instrument_name: " << data["instrument_name"]       << "\n";

}

Prints

jsonrpc:                     "2.0"
methdo:                      "subscription"
params.channel:              "book.BTC-PERPETUAL.raw"
params.data:                 {"type":"change","timestamp":1635513739435,"prev_change_id":6807100702,"instrument_name":"BTC-PERPETUAL","change_id":6807100703,"bids":[["new",6.0772E4,5E1],"demo"],"asks":[]}
params.data.timestamp:       1635513739435
params.data.instrument_name: "BTC-PERPETUAL"
bid: ["new",6.0772E4,5E1]
bid: "demo"

Adding the asks/bids:

for (auto& bid : data["bids"].as_array()) {
    std::cout << "bid: " << bid << "\n";
}
for (auto& ask : data["asks"].as_array()) {
    std::cout << "ask: " << ask << "\n";
}

Prints

bid: ["new",6.0772E4,5E1]
bid: "demo"

Alternative / Bonus

You can also use value_to conversion to your own types:

struct request {
    std::string jsonrpc, method;
    struct params_t {
        std::string channel;
        struct data_t {
            std::string type;
            size_t timestamp, prev_change_id, change_id;
            std::string instrument_name;
            std::vector<json::value> bids, asks;
        } data;
    } params;
};

See it Live

Or flattened:

struct request {
    using values = std::vector<json::value>;
    std::string jsonrpc, method, channel, type, instrument_name;
    size_t      timestamp, prev_change_id, change_id;
    values      bids, asks;

    friend request tag_invoke(json::value_to_tag<request>, json::value const& v)
    {
        auto& params = v.at("params");
        auto& data   = params.at("data");
        return request{
            value_to<std::string>(v.at("jsonrpc")),
            value_to<std::string>(v.at("method")),
            value_to<std::string>(params.at("channel")),
            value_to<std::string>(data.at("type")),
            value_to<std::string>(data.at("instrument_name")),
            value_to<size_t>(data.at("timestamp")),
            value_to<size_t>(data.at("prev_change_id")),
            value_to<size_t>(data.at("change_id")),
            value_to<values>(data.at("bids")),
            value_to<values>(data.at("asks")),
        };
    }
};

See it Live As Well

#include <boost/json.hpp>
#include <boost/json/src.hpp> // header-only for Compiler Explorer
#include <iostream>
namespace json = boost::json;

struct request {
    using values = std::vector<json::value>;
    std::string jsonrpc, method, channel, type, instrument_name;
    size_t      timestamp, prev_change_id, change_id;
    values      bids, asks;

    friend request tag_invoke(json::value_to_tag<request>, json::value const& v)
    {
        auto& params = v.at("params");
        auto& data   = params.at("data");
        return request{
            value_to<std::string>(v.at("jsonrpc")),
            value_to<std::string>(v.at("method")),
            value_to<std::string>(params.at("channel")),
            value_to<std::string>(data.at("type")),
            value_to<std::string>(data.at("instrument_name")),
            value_to<size_t>(data.at("timestamp")),
            value_to<size_t>(data.at("prev_change_id")),
            value_to<size_t>(data.at("change_id")),
            value_to<values>(data.at("bids")),
            value_to<values>(data.at("asks")),
        };
    }
};

int main() {
    auto req = value_to<request>(json::parse(R"({
            "jsonrpc": "2.0",
            "method": "subscription",
            "params": {
                "channel": "book.BTC-PERPETUAL.raw",
                "data": {
                    "type": "change",
                    "timestamp": 1635513739435,
                    "prev_change_id": 6807100702,
                    "instrument_name": "BTC-PERPETUAL",
                    "change_id": 6807100703,
                    "bids": [
                        ["new", 60772.0, 50.0], "demo"],
                    "asks": []
                }
            }
        })"));

    std::cout << "jsonrpc:              " << req.jsonrpc << "\n";
    std::cout << "methdo:               " << req.method << "\n";
    std::cout << "params.channel:       " << req.channel << "\n";
    std::cout << "data.timestamp:       " << req.timestamp << "\n";
    std::cout << "data.instrument_name: " << req.instrument_name << "\n";

    for (auto& bid : req.bids) std::cout << "bid: " << bid << "\n";
    for (auto& ask : req.asks) std::cout << "ask: " << ask << "\n";
}
  • Related