Json: How to programmatically fill an n-th dimensional JSON object?

Created on 4 Mar 2019  路  10Comments  路  Source: nlohmann/json

Hi,

The case is as follows.
In my application i'm receiving text lines. Each lines looks like:

/aaa/bbb/xxx
/aaa/bbb/yyy
/aaa/bbb/zzz

That would be the key structure. The values are also provided. Lets say xxx, yyy, zzz get values of 1, 2, and 3.
This should result in a JSON document that looks like (the parsing i do should make it look like that):

{
  "aaa" : {
    "bbb" : {
      "xxx" : 1,
      "yyy" : 2,
      "zzz" : 3,
  }
}

But i just can't seem to get this done. I must be missing something obvious here.

What i try to do is per input line (say /aaa/bbb/xxx) i split it on "/".
Then i say (somewhat like this):

json jsonDoc;
json &temp = jsonDoc;
for(auto node : {"aaa", "bbb", "xxx"})
{
  temp[node] = {};
  temp = temp[node];
}

As temp is a reference to jsonDoc i'm expecting it to modify the jsonDoc internally (aka, no copies). The output i would expect is:

{
  "aaa" : {
    "bbb" : {
      "xxx" : 1,
  }
}

But instead i get:


Any idea what i might be doing wrong here? And, how to fix it :)

question proposed fix

Most helpful comment

#include <nlohmann/json.hpp>

#include <iomanip>
#include <iostream>

using nlohmann::json;

int main(void)
{
    json j;

    for (auto &p : {"/aaa/bbb/xxx", "/aaa/bbb/yyy", "/aaa/bbb/zzz"})
        j[json::json_pointer(p)] = 1;

    std::cout << std::setw(2) << j << "\n";

    return 0;
}

gives:

{
  "aaa": {
    "bbb": {
      "xxx": 1,
      "yyy": 1,
      "zzz": 1
    }
  }
}

All 10 comments

temp is always a reference to the same json object as jsonDoc so each of the assignments set the whole object to {}.
If you want to keep the code more or less the same, you could use a pointer temp instead of a reference.

@garethsb-sony I don;t think i get it..
I am doing:
temp = temp[node];

For the very reason for temp to not be the same object and basically walk deeper at every iteration.

An assignment to a C++ reference doesn't change the object to which the reference refers. That line of code is exactly the same as jsonDoc = jsonDoc[node];

Not related to your actual problem: If your text lines/index are really in the format: /aaa/bbb/xxx you could use a json_pointer.

(code not tested).

json json;

json["/aaa/bbb/xxx"_json_pointer] = 1;
// or
std::string s = "/aaa/bbb/xxx";
json[json_pointer(s)] = 1;

@garethsb-sony Do you have an example for that? As the code looks quite different of pointers are used.

@pboettch That works but gives me an output i'm not looking for:

{
  "/aaa/bbb/ccc" : 1
}

Not the intention i'm looking for.

#include <nlohmann/json.hpp>

#include <iomanip>
#include <iostream>

using nlohmann::json;

int main(void)
{
    json j;

    for (auto &p : {"/aaa/bbb/xxx", "/aaa/bbb/yyy", "/aaa/bbb/zzz"})
        j[json::json_pointer(p)] = 1;

    std::cout << std::setw(2) << j << "\n";

    return 0;
}

gives:

{
  "aaa": {
    "bbb": {
      "xxx": 1,
      "yyy": 1,
      "zzz": 1
    }
  }
}

It really didn't ought to look very different, if you insist on keeping your current approach.

Untested:

json jsonDoc;
json *temp = &jsonDoc;
for(auto node : {"aaa", "bbb", "xxx"})
{
  (*temp)[node] = {};
  temp = &(*temp)[node];
}

But if you have an input format using json-pointer, @pboettch has shown how easy that is to use.

@pboettch Thank you very much! I did try it with "/xxx/yyy/zzz"_json_pointer and i'm fairly sure that ended up with what i said before. Also, that logic didn't work if i had to use input variables (obviously). But i didn't know about the function version and that seems to work fine.

@garethsb-sony ouch! I try to prevent writing code that looks like that :) I'm going for the much neater json_pointer way.

Thank you both a lot for the help! Also, it might be worth pointing this out on the main json overview page. Even though it might be a bit of a specific corner case.

// closed

Care has to be taken when using your index as a json-pointer. How are / escaped in your "index"-field if they are part of a key?

Care has to be taken when using your index as a json-pointer. How are / escaped in your "index"-field if they are part of a key?

That's no problem as i control the generated data. There is a character being used as seperator and that happens to be "/" for this application.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

asmaloney picture asmaloney  路  4Comments

mlund picture mlund  路  4Comments

edi9999 picture edi9999  路  3Comments

MariaRamos89 picture MariaRamos89  路  4Comments

dcube9 picture dcube9  路  3Comments