Search code examples
jsonparsingboost

Parse elements from json array using boost


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


Solution

  • 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";
    }