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

Add example how to serialize C++ data to JSON #53

Closed
wants to merge 1 commit into from

Conversation

cdeil
Copy link

@cdeil cdeil commented Nov 12, 2014

I don't need to parse JSON, but want to write some data I have as std::string, std:vector<float>, int, ... to JSON.

Is it possible to create and fill a picojson::value object programatically?
(I think this is not covered by the README and the examples ... sorry if I missed it.)

@jfeltz
Copy link

jfeltz commented Nov 11, 2014

@cdeil
picojson.h is fairly readable. Have a look at the picojson::value constructor(s). They are a little peculiar with numeric types, but otherwise it's fairly straightforward, e.g: std::string str("foo"); picojson::value(str).serialize();

@cdeil
Copy link
Author

cdeil commented Nov 11, 2014

OK ... I'll have a look at the header and try to figure it out.

But I would prefer to just learn by having a working example in the picojson/examples folder.
:-)

@jfeltz
Copy link

jfeltz commented Nov 11, 2014

@cdeil
Yes, I actually think the caveats for constructing numeric types should be covered a little in examples, but otherwise this kind of goes with the territory for FOSS libs.

@cdeil
Copy link
Author

cdeil commented Nov 12, 2014

I've attached a commit with examples/cpp_objects_to_json.cc that illustrates what I wanted to do.

I ran into two issue:

  1. picojson::value(int) doesn't work (ambiguity with bool constructor).

Can this be fixed?

  1. picojson::value(std::vector<T>) doesn't work even if picojson::value(T) works.

Can this be implemented?

@cdeil cdeil changed the title Is it possible to create picojson::value objects programatically? Add example how to serialize C++ data to JSON Nov 12, 2014
@cdeil
Copy link
Author

cdeil commented Nov 12, 2014

Another thing that would be nice would be if picojson::value::object item assignments would work like

picojson::value::object data;
data["this"] = "that"; // currently doesn't work

instead of me having to manually wrap everything into picojson::value:

picojson::value::object data;
data["this"] = picojson::value("that"); // currently doesn't work

In json11 this works (see dropbox/json11#20 (comment)) ... unfortunately for the project where I currently need to generate JSON I can't use C++ 11.

I'm not sure if implementing the features I'm proposing here for picojson are just a bit harder in C++ 98 or actually not possible.

Please let me know what is possible / reasonable and I can file a separate issue for each feature request.

@kazuho
Copy link
Owner

kazuho commented Nov 12, 2014

Thank you for the PR. I would look into it laterwards, but please let me first answer the issues raised.

  1. picojson::value(int) doesn't work (ambiguity with bool constructor).
    Can this be fixed?

The answer is no, and it is the outcome of the following reasons.

  • picojson is designed to handle all the supported types (e.g. bool, number, string) through a single interface.
  • a floating point value (double in case of C++) should be used to represent the number type of JSON.
  • the C++ spec. requires the compiler to report an error if it finds code that could cast a int value to either bool or double

Even if there is a way to avoid the issue I would hesitate to implement such hacks, since it would IMO confuse the users since it contradicts from the way C++ is designed (as mentioned in the third point).

  1. picojson::value(std::vector) doesn't work even if picojson::value(T) works.
    Can this be implemented?

I am rather against the idea. First of all as a general guideline, it is not a good idea to provide support for a specific type of container in a library. The preferred way is to use the iterators for generalization so that the logic would not be bound to a certain type of container. So it might be more meaningful to provide a interface like template <typename Iter> picojson::value(Iter first, Iter last), but I wonder if it really helps considering the fact that it would not work in case T is int, since a C++ compiler is required to report an error in such cases where the value can be casted to either bool or int, and that it would be hard for the users of picojson to understand the compiler error in such cases (since the error would be reported as something within picojson).

Another thing that would be nice would be if picojson::value::object item assignments would work like

picojson::value::object data;
data["this"] = "that"; // currently doesn't work

It is unlikely that such a feature would ever be added. Picojson by design requires users to write down explicit code for converting to and from JSON values. As the discussion regarding int suggests, C++ types and JSON types are not necessary interchangable, and my understanding is that supporting implicit conversion in such cases would lead to lesser-readable, hard-to-maintain code at the user side.

@cdeil
Copy link
Author

cdeil commented Nov 12, 2014

@kazuho Thanks for your thoughtful comments!

I still don't understand what the problem would be if explicit value(int n); were added that casts to double as a convenience for the user (see this comment: https://github.com/dropbox/json11/blob/master/json11.hpp#L16)

And I guess this generic way of handling containers is not possible in C++98?
https://github.com/dropbox/json11/blob/master/json11.hpp#L99

@kazuho
Copy link
Owner

kazuho commented Nov 13, 2014

I still don't understand what the problem would be if explicit value(int n); were added that casts to double as a convenience for the user (see this comment: https://github.com/dropbox/json11/blob/master/json11.hpp#L16)

I consider handling int specially to be inconsistent and confusing rather than convenient. The question after handling int specially would be: should we add a special case for long as well? And then for unsigned int, and all other integral value types. I do not think adding endless workarounds is a good idea.

And I guess this generic way of handling containers is not possible in C++98?
https://github.com/dropbox/json11/blob/master/json11.hpp#L99

You are right. IIRC std::enable_if and std::is_convertible were introduced in C++11.

@cdeil
Copy link
Author

cdeil commented Nov 13, 2014

I've started to add some utility functions to my copy of picojson.h to save typing whenever I want to store vectors in JSON (not very well thought out yet ...):

  template <typename T>
  inline value vec_to_json(const std::vector<T> in) {
    value::array out;
    for (unsigned int i=0; i < in.size(); i++) {
      out.push_back(value(in[i]));
    }

    return value(out);
  }

  inline value vec_to_json(const std::vector<int> in) {
    std::vector<double> temp(in.begin(), in.end());
    return vec_to_json(temp);
  }

  inline value num_to_json(double num) {
    const double NA_VALUE = -999;
    num = std::isnan(num) ? NA_VALUE : num;
    return value(num);
  }

@cdeil cdeil closed this Nov 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants