Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to programmatically fill an n-th dimensional JSON object? #1501

Closed
markg85 opened this issue Mar 4, 2019 · 10 comments
Closed

How to programmatically fill an n-th dimensional JSON object? #1501

markg85 opened this issue Mar 4, 2019 · 10 comments
Labels
kind: question solution: proposed fix a fix for the issue has been proposed and waits for confirmation

Comments

@markg85
Copy link

markg85 commented Mar 4, 2019

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:

null

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

@garethsb
Copy link
Contributor

garethsb commented Mar 5, 2019

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.

@markg85
Copy link
Author

markg85 commented Mar 5, 2019

@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.

@garethsb
Copy link
Contributor

garethsb commented Mar 5, 2019

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];

@pboettch
Copy link
Contributor

pboettch commented Mar 5, 2019

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;

@markg85
Copy link
Author

markg85 commented Mar 5, 2019

@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.

@pboettch
Copy link
Contributor

pboettch commented Mar 5, 2019

#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
    }
  }
}

@garethsb
Copy link
Contributor

garethsb commented Mar 5, 2019

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.

@markg85
Copy link
Author

markg85 commented Mar 5, 2019

@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

@markg85 markg85 closed this as completed Mar 5, 2019
@pboettch
Copy link
Contributor

pboettch commented Mar 5, 2019

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?

@markg85
Copy link
Author

markg85 commented Mar 5, 2019

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.

@nlohmann nlohmann added kind: question solution: proposed fix a fix for the issue has been proposed and waits for confirmation labels Mar 10, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind: question solution: proposed fix a fix for the issue has been proposed and waits for confirmation
Projects
None yet
Development

No branches or pull requests

4 participants