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

Ignore nullptr values on constructing json object from a container #1422

Closed
vassilisw opened this issue Jan 10, 2019 · 11 comments
Closed

Ignore nullptr values on constructing json object from a container #1422

vassilisw opened this issue Jan 10, 2019 · 11 comments
Labels
kind: question solution: proposed fix a fix for the issue has been proposed and waits for confirmation

Comments

@vassilisw
Copy link

vassilisw commented Jan 10, 2019

I use void to_json(json& j, const Bar& b) function. In some cases I would like this function to just assign nullptr to j. For example...

void to_json(nlohmann::json& j, const Bar& b) {
    if (b.value == __FLT_MAX__) {
        j = nullptr;
        return;
    }
    j["name"] = b.name;
    j["value"] = b.value;
}
...

    std::vector<Bar> bars;
    bars.emplace_back("b1", 1.234);
    bars.emplace_back("b2", __FLT_MAX__);
    bars.emplace_back("b3", __FLT_MAX__);

    nlohmann::json j(bars);
    std::cout << j.dump(4) << std::endl;

Output...

[
    {
        "name": "b1",
        "value": 1.232
    },
    null,
    null
]

Is there a way for nullptr objects to just get ignored when the json object is created?
Such that the object to be...

[
    {
        "name": "b1",
        "value": 1.232
    }
]

I am aware of the parser_callback_t, anything similar for this?

@vassilisw vassilisw changed the title Ignore nullptr values when constructing json object from vector Ignore nullptr values when constructing json object from a container Jan 10, 2019
@vassilisw vassilisw changed the title Ignore nullptr values when constructing json object from a container Ignore nullptr values on constructing json object from a container Jan 10, 2019
@nlohmann
Copy link
Owner

Unfortunately, this is not possible at the moment (maybe @theodelrieu has an idea).

In the meantime, you can employ the erase-remove idiom to remove null values, just like it is possible for std::vector:

j.erase(std::remove(j.begin(), j.end(), nullptr), j.end());

@nlohmann nlohmann added kind: question solution: proposed fix a fix for the issue has been proposed and waits for confirmation labels Jan 11, 2019
@FrancoisChabot
Copy link
Contributor

FrancoisChabot commented Jan 21, 2019

Another way to do this would be to provide an explicit to_json() for std::vector<Bar>, and apply the filter there:

void to_json(nlohmann::json& j, const Bar& b) {
    j["name"] = b.name;
    j["value"] = b.value;
}

void to_json(nlohmann::json& j, const std::vector<Bar>& b) {
  for(const auto& i : b) {
    if(i.value == __FLT_MAX__) {continue;}
    j.push_back(i);
  }
}

@vassilisw
Copy link
Author

@FrancoisChabot very nice workaround indeed!

@nlohmann
Copy link
Owner

@vassilisw Does this solve your issue?

@vassilisw
Copy link
Author

Yes it does, thanks (sorry for not closing).

@TomGarden
Copy link

TomGarden commented Mar 24, 2023

Unfortunately, this is not possible at the moment (maybe @theodelrieu has an idea).

In the meantime, you can employ the erase-remove idiom to remove null values, just like it is possible for std::vector:

j.erase(std::remove(j.begin(), j.end(), nullptr), j.end());

@nlohmann
Hello , I try the code , I get err data . my nlohmann lib version '3.11.2'

  • I what to filter json data , del null element , get not null element json obj .
  • my env
    • gcc (Debian 10.2.1-6) 10.2.1 20210110
    • Debian GNU/Linux 11 (bullseye)
    • C++ STL 20
  • my test code : https://godbolt.org/z/WY98be9v3
  • no build err , data err .

you have any suggest ?

thanks .

  nlohmann::json jObj = R"(
    {
      "callback": null,
      "city": null,
      "citylimit": null,
      "datatype": null,
      "key": "123123123",
      "keywords": "123123123",
      "location": "1.1.123",
      "output": "JSON",
      "sig": null,
      "type": null
    }
    )"_json;
  jObj.erase(std::remove(jObj.begin(), jObj.end(), nullptr), jObj.end());
  std::cout << jObj.dump(2) << std::endl;
/* expected output */
{
      "key": "123123123",
      "keywords": "123123123",
      "location": "1.1.123",
      "output": "JSON",
}

/* actual output */
{
      "callback": "123123123",
      "city": "123123123",
      "citylimit": "1.1.123",
      "datatype": "JSON"
}   

@TomGarden
Copy link

my last code

  nlohmann::json& clearNull(nlohmann::json& jObj) {

    nlohmann::json jClone = jObj;
    jObj.clear();

    for (const auto& item : jClone.items()) {
      if (item.value().is_object()) {
        nlohmann::json jSubObj = clearNull(item.value());
        if (!jSubObj.empty()) jObj[item.key()] = jSubObj;
      } else if (!item.value().is_null()) {
        jObj[item.key()] = item.value();
      }
    }

    return jObj;
  }

@nlohmann
Copy link
Owner

@TomGarden

In order to asses your issue, we need the following information:

  • What is the issue you have?

  • Please describe the steps to reproduce the issue. Can you provide a small but working code example?

  • What is the expected behavior?

  • And what is the actual behavior instead?

  • Which compiler and operating system are you using? Is it a supported compiler?

  • Did you use a released version of the library or the version from the develop branch?

  • If you experience a compilation error: can you compile and run the unit tests?

@lingxd
Copy link

lingxd commented Nov 26, 2024

my last code

  nlohmann::json& clearNull(nlohmann::json& jObj) {

    nlohmann::json jClone = jObj;
    jObj.clear();

    for (const auto& item : jClone.items()) {
      if (item.value().is_object()) {
        nlohmann::json jSubObj = clearNull(item.value());
        if (!jSubObj.empty()) jObj[item.key()] = jSubObj;
      } else if (!item.value().is_null()) {
        jObj[item.key()] = item.value();
      }
    }

    return jObj;
  }
nlohmann::json &clear_null(nlohmann::json &j)
{
    nlohmann::json j_clone = j;
    j.clear();

    for (const auto& item : j_clone.items()) {
        if (item.value().is_object()) {
            nlohmann::json jSubObj = clear_null(item.value());
            if (!jSubObj.empty()) j[item.key()] = jSubObj;
        } else if (item.value().is_array()) {
            nlohmann::json jSubArray = item.value();
            jSubArray.erase(std::remove_if(jSubArray.begin(), jSubArray.end(), [](const nlohmann::json& el) {
                                return el.is_null(); 
                            }), jSubArray.end());
            for (json::iterator it = jSubArray.begin(); it != jSubArray.end(); ++it) {
                clear_null(*it);
            }
            if (!jSubArray.empty()) j[item.key()] = jSubArray;
        } else if (!item.value().is_null()) {
            j[item.key()] = item.value();
        }
    }

    return j;
}

if array is null need to erase.

@lingxd
Copy link

lingxd commented Nov 26, 2024

Unfortunately, this is not possible at the moment (maybe @theodelrieu has an idea).

In the meantime, you can employ the erase-remove idiom to remove null values, just like it is possible for std::vector:

j.erase(std::remove(j.begin(), j.end(), nullptr), j.end());

thanks, I use version 3.11.3 to use boost::optional, this is my code

NLOHMANN_JSON_NAMESPACE_BEGIN
template <typename T>
void to_json(json& j, const boost::optional<T>& opt) {
    if (opt) {
        j = *opt;
    } else {
        std::cout << j.dump() << std::endl;
    }
}

template <typename T>
void from_json(const json& j, boost::optional<T>& opt) {
    if (j.is_null()) {
        opt = boost::none;
    } else {
        opt = j.template get<T>();
    }
}

NLOHMANN_JSON_NAMESPACE_END

What I want to ask is that in the case of opt::none, will the value of null be filled in the default?

{
    "json": null
}

@gregmarr
Copy link
Contributor

nlohmann::json &clear_null(nlohmann::json &j)
{
    nlohmann::json j_clone = j;
    j.clear();

That's an unnecessary copy. This just uses moves:

nlohmann::json &clear_null(nlohmann::json &j)
{
    nlohmann::json j_clone;
    std::swap(j, j_clone);

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

6 participants