5

I have this code that I need to parse/or get the JSON array as std::string to be used in the app.

std::string ss = "{ \"id\" : \"123\", \"number\" : \"456\", \"stuff\" : [{ \"name\" : \"test\" }] }";

ptree pt2;
std::istringstream is(ss);
read_json(is, pt2);
std::string id = pt2.get<std::string>("id");
std::string num= pt2.get<std::string>("number");
std::string stuff = pt2.get<std::string>("stuff"); 

What is needed is the "stuff" to be retrieved like this as std::string [{ "name" : "test" }]

However the code above stuff is just returning empty string. What could be wrong

Barry
  • 286,269
  • 29
  • 621
  • 977
xkm
  • 271
  • 2
  • 4
  • 11
  • [OT]: Good place to use raw string here: `ss = R"({ "id":"123", "number":"456", "stuff":[{"name":"test"}] })"`. – Jarod42 Jul 10 '15 at 16:40

3 Answers3

7

Arrays are represented as child nodes with many "" keys:

docs

  • JSON arrays are mapped to nodes. Each element is a child node with an empty name. If a node has both named and unnamed child nodes, it cannot be mapped to a JSON representation.

Live On Coliru

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

using boost::property_tree::ptree;

int main() {
    std::string ss = "{ \"id\" : \"123\", \"number\" : \"456\", \"stuff\" : [{ \"name\" : \"test\" }, { \"name\" : \"some\" }, { \"name\" : \"stuffs\" }] }";

    ptree pt;
    std::istringstream is(ss);
    read_json(is, pt);

    std::cout << "id:     " << pt.get<std::string>("id") << "\n";
    std::cout << "number: " << pt.get<std::string>("number") << "\n";
    for (auto& e : pt.get_child("stuff")) {
        std::cout << "stuff name: " << e.second.get<std::string>("name") << "\n";
    }
}

Prints

id:     123
number: 456
stuff name: test
stuff name: some
stuff name: stuffs
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Is it possible to get it like '[{ "name" : "some" }, { "name" : "stuffs" }]' <-- this – xkm Jul 10 '15 at 17:32
  • 1
    @xkm Yes. `write_json(some_stream, pt.get_child("stuff"));`. Make `some_stream` a `std::ostringstream` so you can use `some_stream.str()` to get the text – sehe Jul 11 '15 at 09:19
  • @sehe I would like to do it without the auto& e for loop. Can we not access the elements as pt.get_child("stuff").name[0] and it gives value test. – user3217310 Jan 13 '21 at 07:00
1

Since "stuff" is an array, you can iterate over the elements of it, which are dictionaries. And then you can iterate over the elements of the dictionary, which are key-value pairs:

for (const auto& dict : pt2.get_child("stuff")) {
    for (const auto& kv : dict.second) {
        std::cout << "key = " << kv.first << std::endl;
        std::cout << "val = " << kv.second.get_value<std::string>() << std::endl;
    }
}
Barry
  • 286,269
  • 29
  • 621
  • 977
1

continue with @sehe 's answer, related to the question asked by @xkm

Is it possible to get it like '[{ "name" : "some" }, { "name" : "stuffs" }]'

Yes, you can. Just treat it with an "unnamed" key which means the key with empty string.

f.g.

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

#include <iostream>

using boost::property_tree::ptree;

int main()
{
    std::stringstream ss;
    ss << R"([{"a": 5}, {"a": 9}])";

    ptree pt;
    read_json(ss, pt);
    for (auto& item : pt.get_child(""))
       std::cout << "value is " << item.second.get<int>("a") << std::endl;
}
eshenhu
  • 31
  • 3