Home > Blockchain >  How to parse below JSON with nested array in C and retrieve the result
How to parse below JSON with nested array in C and retrieve the result

Time:02-04

I have a JSON like below which need to be parsed in C using read_json.

[
  {
    "key": "123",
    "revoked": false,
    "metadata": [
      {
        "visible": true,
        "key": "abc",
        "value": "0"
      },
      {
        "visible": true,
        "key": "cdf",
        "value": "0"      
      }     
    ],
    "meterAttributes": []
  }
]

In the above JSON, metadata and its key/value to be retrieved.

boost::property_tree::read_json(jsonString, pt);
for (auto& outerArray : pt)
    {
        for (auto& arrayProperty : outerArray.second)
        {
            if (arrayProperty.first == ws2s(metadata))
            {

The above code doesn't brought up the result as expected.

CodePudding user response:

Here's one way:

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

int main() {
    std::istringstream is(
        R"aw([{ "key": "123", "revoked": false, "metadata": [ { "visible": true, "key": "abc", "value": "0" }, { "visible": true, "key": "cdf", "value": "0" }], "meterAttributes": [] } ])aw");

    boost::property_tree::ptree pt;
    boost::property_tree::read_json(is, pt);
    //boost::property_tree::write_json(std::cout, pt); // debug

    for (auto& outerArray : pt) {
        auto mit = outerArray.second.find("metadata"); // use find

        for (auto& [mkey, mvalue] : mit->second) {
            std::cout << "---\n";
            for (auto& [key, value] : mvalue) {
                std::cout << key << " = " << value.data() << '\n';
            }
        }
    }
}

Output

---
visible = true
key = abc
value = 0
---
visible = true
key = cdf
value = 0

A similar piece of code using nlohmann/json.hpp or any other dedicated JSON library could look like below:

#include <nlohmann/json.hpp>
#include <iostream>
#include <sstream>

int main() {
    std::istringstream is(
        R"aw([{ "key": "123", "revoked": false, "metadata": [ { "visible": true, "key": "abc", "value": "0" }, { "visible": true, "key": "cdf", "value": "0" }], "meterAttributes": [] } ])aw");

    nlohmann::json j;
    is >> j;
    
    //std::cout << j[0]["metadata"].dump(2) << "\n\n"; // debug

    for(auto& v : j[0]["metadata"]) {
        std::cout << "---\n";
        std::cout << v["visible"] << '\n';
        std::cout << v["key"] << '\n';
        std::cout << v["value"] << '\n';
    }
}

Output

---
true
"abc"
"0"
---
true
"cdf"
"0"

CodePudding user response:

I'd suggest Boost JSON:

#include <boost/json.hpp>
#include <fmt/ranges.h>
#include <iostream>
namespace json = boost::json;

int main() {
    std::map<std::string, std::string> kv;

    auto doc = json::parse(sample);
    for (auto& toplevel : doc.as_array()) {
        for (auto& md : toplevel.at("metadata").as_array()) {
            kv.emplace(md.at("key").as_string(), md.at("value").as_string());
        }
    }

    fmt::print("Parsed: {}\n", kv);
}

Printing: Live On Compiler Explorer

Parsed: {("abc", "0"), ("cdf", "0")}

Alternative

If you insist on using Boost PropertyTree (e.g. because your data represents a property tree): Live On Compiler Explorer

#include <boost/property_tree/json_parser.hpp>
#include <fmt/ranges.h>
#include <map>

int main() {
    std::map<std::string, std::string> kv;

    boost::property_tree::ptree doc;
    std::istringstream          is(sample);
    read_json(is, doc);

    for (auto& [_, toplevel] : doc) {
        for (auto& [_, md] : toplevel.get_child("metadata")) {
            kv.emplace(md.get("key", ""), md.get("value", ""));
        }
    }

    fmt::print("Parsed: {}\n", kv);
}

Printing the same.

  •  Tags:  
  • Related