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

is it possible to check existence of a value deep in hierarchy? #584

Closed
crusader-mike opened this issue May 15, 2017 · 8 comments
Closed

Comments

@crusader-mike
Copy link

crusader-mike commented May 15, 2017

Smth like this:

json j = ...;
if (j.find("/this/that/then"_json_pointer) != j.end()) ...;

I can use j.value(ptr, def_value), but then I can't tell if node actually existed. I can use j.at(...) -- but I don't want to deal with exceptions.

Edit: j.value() approach doesn't seem to work either...

@nlohmann
Copy link
Owner

No, this is currently not possible without exceptions.

@crusader-mike
Copy link
Author

thank you

@nlohmann
Copy link
Owner

You may try the following:

auto j_flatten = json::flatten(j);
if (j_flatten.find("/this/that/then") != j_flatten.end())
  ...

I think flatten does not use exceptions. It may be less performant, but still...

@crusader-mike
Copy link
Author

No, this is way too expensive (and it also throws, just in different circumstances (out of memory).

@nlohmann
Copy link
Owner

I see. Then I fear you have to be patient until we add more support for situations where exceptions are switched off.

May I ask in which situation you are using the library?

@crusader-mike
Copy link
Author

crusader-mike commented May 16, 2017

cmdline app that receives a 'job definition' json, checks few values at various places in the tree (tweaks few things, if need be) and submits it for execution to another portion of code (aka engine).

Btw, few notes:

  • from_json() receives reverence to already constructed struct. Which means we are doing unnecessary work (member variables written in default ctor will be overwritten). It can be implemented in better way:
    template<class T> T from_json(json const& j) { ... }
    users can provide their own specializations, ideally smth like:
MyStruct::MyStruct(json const& j) : var1(j.value("var1", "ABC"))
{
}
template<> MyStruct from_json<MyStruct>(json const& j) { return MyStruct(j); }

you could make it even faster if you assume that next field is likely to follow previously found one and provide hint to subsequent lookup. Basically, if user's json has same layout as related struct in memory -- there will be no search at all.

  • In current from_json() form I have to deal with default value in this way:
struct MyStruct
{
    string var1{"ABC"};    // default value
};

void from_json(json const& j, MyStruct& v)
{
     v.var1 = j.value("var1", "ABC");   //... but I don't want default value to be repeated in two places (too easy to forget to update second one)

    v.var1 = j.value("var1", v.var1); //... but why should I pay (making string copy, passing second param) if value exists in the json?

   if (j.count("var1"))
        v.var1 = j["var1"];   // ... but I don't like doing two lookups to get one value
}

Is there a better way? Or maybe in case 2 it is guaranteed that default value is passed by reference and operator[] is inline?

@krisives
Copy link

krisives commented Sep 14, 2018

Here is a snippet using C++11 or later:

Example:

nlohnmann::json obj = nlohmann::parse("{'foo': 'bar': {'baz': 100}}");
nlohnmann::json deep = Util::resolve(obj, {"music", "ytcracker", "baz"});
nlohmann::json Util::resolve(nlohmann::json obj, std::initializer_list<std::string> keys) {
  nlohmann::json j = obj;

  for (auto& key : keys) {
    if (!j.is_object()) {
      return nlohmann::json();
    }

    auto exists = j.find(key);

    if (exists == j.end()) {
      return nlohmann::json();
    }

    j = *exists;
  }

  return j;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants