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 check if a key exists without silently generating null objects on the path #2041

Closed
Survivor6666 opened this issue Apr 14, 2020 · 4 comments
Labels
kind: question solution: proposed fix a fix for the issue has been proposed and waits for confirmation

Comments

@Survivor6666
Copy link

I have a deep nested JSON data model with a lot of optional keys and optional sub- structures.
When trying to read a non-existing optional key in a not yet existing path the library silently creates this path. When parts of the branch are not existing 'null' keys / 'null' structures are silently generated into the JSON model.

Even checking for a key generates the elements on its path:

...
if (jm["Elements"]["Comments"].contains("Comment")
{ /* Key is existing */
   bOk = !FALSE;
}
...

This generates following JSON output:

{
   "Elements": {
      "Comments": null
   }
}

I tried also the 'find' method with the same result. Addressing a non-existing key generates it.
To check each sub-level with 'contain' or 'find' before accessing the next sub-key is not a real option
because the nesting depth is 10 and the model contains a few thousand 1000 optional keys.

Is there any hint how to check if a key exists without checking each key on its path?

Any help is welcome
Christian

@nlohmann
Copy link
Owner

The contains function does that.

@nlohmann nlohmann added the solution: proposed fix a fix for the issue has been proposed and waits for confirmation label Apr 14, 2020
@Survivor6666
Copy link
Author

I used the contains method in the example above. The JSON object was initially empty .
Checking with 'contains' in the not before existing ["Elements"]["Comments"] 'path' for the key ["Comment"] generates the content of the JSON output above including the "Comments": null pair.

I could check step-by-step if ["Elements"] exists, then if ["Comments"] exists and finally if ["Comment"] exists. My hope is that I can check for the last key without generating the others.
My model is really huge and this step-by-step generates many lines of code.

@nlohmann
Copy link
Owner

You mix operator[] and contains. The former does create elements, the latter does not.

You need to go

if (jm.contains("Elements") and jm["Elements"].contains("Comments") and jm["Elements]["Comments"].contains("Comment")
{ /* Key is existing */
   bOk = !FALSE;
}

Alternatively, you may want to try JSON Pointers:

if (jm.cointains("/Elements/Comments/Comment"_json_pointer)
{...}

@Survivor6666
Copy link
Author

Json Pointer is the solution :-)

if (jm.cointains("/Elements/Comments/Comment"_json_pointer)
{...}

The first proposal needs to be slightly modified.
The tests in the if condition are all called even if the first test (jm.contains("Elements")) is FALSE.
So the following tests generate the keys. Nested 'if' calls would work.

Ok, from today Json pointers are my friends.
Thanks for the lightspeed fast solution.

Christian

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

2 participants