使用 boost 从 json 读取缓冲区

Reading a buffer from a json using boost

我有以下 json 字符串:

{"message":
{"type":"Buffer",
"data":[0,0,0,193,0,41,10,190,1,34,128,0,0,1,38,0,0,1,232,41,40,202,35,104,81,66,0,162,194,173,0,254,67,116,38,60,235,70,250,195,139,141,184,47,167,240,210,207,118,184,140,225,82,52,30,35,111,80,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,115,33,2,155,92,51,188,68,15,123,37,47,245,59,120,114,102,60,233,15,212,39,112,165,190,210,14,188,25,156,234,124,154,181,101,118,71,48,69,2,33,0,242,181,45,125,208,73,206,26,86,183,220,28,159,36,149,124,208,72,187,118,116,44,224,252,192,173,242,248,112,181,63,49,2,32,84,83,33,39,113,80,183,50,225,212,133,84,226,26,173,185,65,216,237,234,90,20,215,136,184,246,229,230,13,227,69,42]},
"validator_key":"n9MZdq6qPssK3jw63sjR8VRR4NjyCmaV11LnqTiCFQjRCDFreUVc\n"}

我需要读取字段 message.data,这是一个通过 gRPC 来自 node.js 进程的缓冲区。我试过这样的事情:

        std::stringstream ss;
        boost::property_tree::ptree pt;
        ss << gossip.message();

        boost::property_tree::read_json(ss, pt);
        auto message_received = pt.get<std::string>("message.data");

        std::cout << "Message received pure: " << gossip.message() << std::endl;
        std::cout << "Message received, json: " << message_received << std::endl;

gossip.message() 是我的 json 字符串,因为它是通过 gRPC 接收的。结果如下:

Message received pure: {"message":{"type":"Buffer","data":[0,0,0,193,0,41,10,190,1,34,128,0,0,1,38,0,0,1,232,41,40,202,35,104,81,66,0,162,194,173,0,254,67,116,38,60,235,70,250,195,139,141,184,47,167,240,210,207,118,184,140,225,82,52,30,35,111,80,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,115,33,2,155,92,51,188,68,15,123,37,47,245,59,120,114,102,60,233,15,212,39,112,165,190,210,14,188,25,156,234,124,154,181,101,118,71,48,69,2,33,0,242,181,45,125,208,73,206,26,86,183,220,28,159,36,149,124,208,72,187,118,116,44,224,252,192,173,242,248,112,181,63,49,2,32,84,83,33,39,113,80,183,50,225,212,133,84,226,26,173,185,65,216,237,234,90,20,215,136,184,246,229,230,13,227,69,42]},"validator_key":"n9MZdq6qPssK3jw63sjR8VRR4NjyCmaV11LnqTiCFQjRCDFreUVc\n"}
Message received, json: 

如何读取该字段并将其放入 std::string 或 asio 缓冲区?

两个问题:

  • message.data 不是字符串。这是一个整数数组。

  • Boost 属性 树不是 JSON 库。

假设您希望“字符串”由在数组中表示为无符号整数值的字节组成。

一个修复,一个解决方法:

修复

使用 JSON 库,例如 Boost JSON:

Live On Compiler Explorer

#include <boost/json.hpp>
#include <boost/json/src.hpp>
#include <iostream>

struct Gossip { std::string message(); } gossip;

int main()
{
    namespace json = boost::json;
    auto doc = json::parse(gossip.message()).as_object();

    auto& arr   = doc["message"].as_object()["data"];
    auto  bytes = json::value_to<std::vector<uint8_t>>(arr);
    std::string text(bytes.begin(), bytes.end());

    //std::cout << "message(): " << gossip.message() << "\n";
    std::cout << "doc:       " << doc              << "\n";
    std::cout << "arr:       " << arr              << "\n";
    std::cout << "bytes:     ";

    for (int val : bytes)
        std::cout << " " << val;

    std::cout << "\ntext: " << std::quoted(text) << "\n";
}

std::string Gossip::message() {
    return R"({
    "message": {
        "type": "Buffer",
        "data": [0, 0, 0, 193, 0, 41, 10, 190, 1, 34, 128, 0, 0, 1, 38, 0, 0, 1, 232, 41, 40, 202, 35, 104, 81, 66, 0, 162, 194, 173, 0, 254, 67, 116, 38, 60, 235, 70, 250, 195, 139, 141, 184, 47, 167, 240, 210, 207, 118, 184, 140, 225, 82, 52, 30, 35, 111, 80, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 33, 2, 155, 92, 51, 188, 68, 15, 123, 37, 47, 245, 59, 120, 114, 102, 60, 233, 15, 212, 39, 112, 165, 190, 210, 14, 188, 25, 156, 234, 124, 154, 181, 101, 118, 71, 48, 69, 2, 33, 0, 242, 181, 45, 125, 208, 73, 206, 26, 86, 183, 220, 28, 159, 36, 149, 124, 208, 72, 187, 118, 116, 44, 224, 252, 192, 173, 242, 248, 112, 181, 63, 49, 2, 32, 84, 83, 33, 39, 113, 80, 183, 50, 225, 212, 133, 84, 226, 26, 173, 185, 65, 216, 237, 234, 90, 20, 215, 136, 184, 246, 229, 230, 13, 227, 69, 42]
    },
    "validator_key": "n9MZdq6qPssK3jw63sjR8VRR4NjyCmaV11LnqTiCFQjRCDFreUVc\n"
})";
}

使用 Boost 属性 树

的解决方法
std::string message_received;

for (auto& [k, v] : pt.get_child("message.data")) {
    message_received += static_cast<char>(v.get_value<unsigned short>());
}

生成的数据与任何(我所知的)文本编码都不相似,但这可能无关紧要。

Live On Compiler Explorer

#include <boost/property_tree/json_parser.hpp>
#include <iostream>

struct Gossip { std::string message(); } gossip;

int main()
{
    boost::property_tree::ptree pt;

    {
        std::stringstream ss(gossip.message());
        boost::property_tree::read_json(ss, pt);
    }

    std::string message_received;
    for (auto& [k, v] : pt.get_child("message.data")) {
        message_received += static_cast<char>(v.get_value<unsigned short>());
    }

    std::cout << "Message received pure: " << gossip.message() << std::endl;
    std::cout << "Message received, json: " << message_received << std::endl;
}

std::string Gossip::message() {
    return R"({
    "message": {
        "type": "Buffer",
        "data": [0, 0, 0, 193, 0, 41, 10, 190, 1, 34, 128, 0, 0, 1, 38, 0, 0, 1, 232, 41, 40, 202, 35, 104, 81, 66, 0, 162, 194, 173, 0, 254, 67, 116, 38, 60, 235, 70, 250, 195, 139, 141, 184, 47, 167, 240, 210, 207, 118, 184, 140, 225, 82, 52, 30, 35, 111, 80, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 33, 2, 155, 92, 51, 188, 68, 15, 123, 37, 47, 245, 59, 120, 114, 102, 60, 233, 15, 212, 39, 112, 165, 190, 210, 14, 188, 25, 156, 234, 124, 154, 181, 101, 118, 71, 48, 69, 2, 33, 0, 242, 181, 45, 125, 208, 73, 206, 26, 86, 183, 220, 28, 159, 36, 149, 124, 208, 72, 187, 118, 116, 44, 224, 252, 192, 173, 242, 248, 112, 181, 63, 49, 2, 32, 84, 83, 33, 39, 113, 80, 183, 50, 225, 212, 133, 84, 226, 26, 173, 185, 65, 216, 237, 234, 90, 20, 215, 136, 184, 246, 229, 230, 13, 227, 69, 42]
    },
    "validator_key": "n9MZdq6qPssK3jw63sjR8VRR4NjyCmaV11LnqTiCFQjRCDFreUVc\n"
})";
}