4

I am working with https://github.com/nlohmann/json and it works well. However I am finding difficulties to create the following json outout

 {
    "Id": 1,
    "Child": [
        {
            "Id": 2
        },
        {
            "Id": 3,
            "Child": [
                {
                  "Id" : 5
                },
                {
                  "Id" : 6
                }
            ]
        },
        {
            "Id": 4
        }
    ]
}

Every node must have an id and an array ("Child" element). Any child can recursively continue to have Id or Child. The json above is just an example. What I want is to create a chain between father and children node using nlohmann json.

Numbers 1, 2, 3, .... are picked up randomly. We don't care for now about those values.

Any idea how to create it?

Code so far

#include <iostream>
#include <string>
#include <vector>
#include "json.hpp"

using json = nlohmann::json;


struct json_node_t {

    int id;
    std::vector<json_node_t> child;
};


int main( int argc, char** argv) {

    json j;

    for( int i = 0; i < 3; i++) {

        json_node_t n;

        n.id = i;
        j["id"] = i;

        if ( i < 2 ) {

            j["child"].push_back(n);


        }


    }


    return 0;

}
cateof
  • 6,608
  • 25
  • 79
  • 153
  • How are we supposed to infer that 5 and 6 should be children of 3 and not, say, 2? This post has many of the same problems your last question (https://stackoverflow.com/questions/45882363/c-create-json-output-from-a-tree-like-input) had. – AndyG Aug 25 '17 at 14:47
  • I don't really care about the values of the id elements. I just want to find out how to create a recursive representation of data using nlohmann json – cateof Aug 25 '17 at 14:50

1 Answers1

5

In order to serialize your own type, you need to implement a to_json function for that type.

#include <iostream>
#include <string>
#include <vector>
#include "json.hpp"

using namespace std;
using json = nlohmann::json;

struct json_node_t {
    int id;
    std::vector<json_node_t> child;
};

void to_json(json& j, const json_node_t& node) {
    j = {{"ID", node.id}};
    if (!node.child.empty())
        j.push_back({"children", node.child});
}

int main() {
    json_node_t node = {1, {{2, {}}, {3, {{5, {}}, {6, {}}}}, {4, {}}}};
    json j = node;

    cout << j.dump(2) << endl;
    return 0;
}

Output:

{
  "ID": 1,
  "children": [
    {
      "ID": 2
    },
    {
      "ID": 3,
      "children": [
        {
          "ID": 5
        },
        {
          "ID": 6
        }
      ]
    },
    {
      "ID": 4
    }
  ]
}

A couple of more ways to initialize json_node_t (all producing the same tree and the same output):

struct json_node_t {
    int id;
    std::vector<json_node_t> child;
    json_node_t(int node_id, initializer_list<json_node_t> node_children = initializer_list<json_node_t>());
    json_node_t& add(const json_node_t& node);
    json_node_t& add(const initializer_list<json_node_t>& nodes);
};

json_node_t::json_node_t(int node_id, initializer_list<json_node_t> node_children) : id(node_id), child(node_children) {
}

json_node_t& json_node_t::add(const json_node_t& node) {
    child.push_back(node);
    return child.back();
}

json_node_t& json_node_t::add(const initializer_list<json_node_t>& nodes) {
    child.insert(child.end(), nodes);
    return child.back();
}

int main() {
    json_node_t node_a = {1, {{2, {}}, {3, {{5, {}}, {6, {}}}}, {4, {}}}};

    json_node_t node_b = {1, {2, {3, {5, 6}}, 4}};

    json_node_t node_c(1);
    node_c.add(2);
    node_c.add(3).add({5, 6});
    node_c.add(4);

    cout << json(node_a).dump(2) << endl << endl;
    cout << json(node_b).dump(2) << endl << endl;
    cout << json(node_c).dump(2) << endl;
    return 0;
}
Anton
  • 3,113
  • 14
  • 12
  • thanks. Looks OK to use the to_json method. However I find it difficult to create nodes. This initialization works OK {1, {{2, {}}, {3, {{5, {}}, {6, {}}}}, {4, {}}}}; but is there any easier way to add nodes, ie add children at the parent? – cateof Aug 31 '17 at 19:55
  • 1
    @cateof Since `json_node_t` is your class, you can add any convenience methods suitable for the intended usage. I added a couple of examples into the answer. – Anton Aug 31 '17 at 23:38