4

I'm trying to use Boost's property tree to parse a JSON-file. Here is the JSON-file

{
    "a": 1,
    "b": [{
        "b_a": 2,
        "b_b": {
            "b_b_a": "test"
        },
        "b_c": 0,
        "b_d": [{
            "b_d_a": 3,
            "b_d_b": {
                "b_d_c": 4
            },
            "b_d_c": "test",
            "b_d_d": {
                "b_d_d": 5
            }
        }],
        "b_e": null,
        "b_f": [{
            "b_f_a": 6
        }],
        "b_g": 7
    }],
    "c": 8
}

and a MWE

#include <iostream>
#include <fstream>

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

namespace pt = boost::property_tree;

using namespace std;

int main()
{

    boost::property_tree::ptree jsontree;
    boost::property_tree::read_json("test.json", jsontree);

    int v0 = jsontree.get<int>("a");
    int v1 = jsontree.get<int>("c");
}

Question I currently know how to read the outermost variables a and c. However, I'm having difficulty reading other levels such as b_a, b_b_a, b_d_a and so on. How can I do this with Boost? I'm not necessarily looking for a solution involving loops, merely trying to figure out how to "extract" inner variables.

I am open to using other libraries if they are optimal. But so far Boost looks promising to me.

BillyJean
  • 1,537
  • 1
  • 22
  • 39
  • You can use "." separator to specify path to nested nodes like `jsontree.get("b.b_b.b_b_a")` – zett42 May 01 '17 at 19:48
  • 1
    For JSON, I'd generally recommend one of two possibilities. If you're doing something like a REST server that needs to operate on *massive* amounts of JSON as fast as humanly possible, you want [RapidJSON](https://github.com/miloyip/rapidjson). For nearly everything else, you probably want [Nlohmann's JSON library](https://github.com/nlohmann/json). – Jerry Coffin May 01 '17 at 19:49
  • @zett42 I tried it out, I get an error: `terminate called after throwing an instance of 'boost::exception_detail::clone_impl >' what(): No such node (b.b_b.b_b_a)` – BillyJean May 01 '17 at 19:53
  • @JerryCoffin Thanks, I like that Nlohmann's JSON library is easily added to a project. I'm missing a bunch of examples though to figure out how to parse my file, I didn't find any useful at the main site – BillyJean May 01 '17 at 20:11
  • 1
    Using Nlohmann's library, retrieving `b_d_a` would be something like: `json j = json::parse(input_string); std::cout << j["b"]["b_d"]["b_d_a"];` – Jerry Coffin May 01 '17 at 20:15
  • 1
    You got the error because I missed the fact that child node `b` is an array. See my answer. – zett42 May 01 '17 at 20:24
  • 1
    @Jerry I think you would need something like `j["b"][0]["b_d"][0]["b_d_a"]` because both `b` and `b_d` are arrays. I don't know if this syntax is valid though. – zett42 May 01 '17 at 20:42
  • 1
    @zett42: Oh, quite right (I didn't read the JSON carefully enough). And yes, what you wrote should be fine. – Jerry Coffin May 01 '17 at 20:44

1 Answers1

4

To get nested elements you can use the path syntax where each path component is separated by ".". Things are a little bit more complicated here because the child node b is an array. So you can't do without a loop.

const pt::ptree& b = jsontree.get_child("b");
for( const auto& kv : b ){
    cout << "b_b_a = " << kv.second.get<string>("b_b.b_b_a") << "\n";    
}

Live demo at Coliru.

I've also added code to print the whole tree recursively so you can see how the JSON gets translated to the ptree. Arrays elements are stored as key/value pairs where the key is an empty string.

zett42
  • 25,437
  • 3
  • 35
  • 72