akheron / jansson

C library for encoding, decoding and manipulating JSON data
http://www.digip.org/jansson/
Other
3.05k stars 808 forks source link

Feature request: "magic" object attributes with ad-hoc dumping routines. #595

Closed bstarynk closed 2 years ago

bstarynk commented 2 years ago

Hello all,

A feature potentially useful for RefPerSys, and probably for many other projects using JSON with Jansson

In some JSON objects and some cases, it makes no sense to dump a given JSON number with a lot of digits after the decimal point.

As a concrete example, any JSON value representing some "macroscopic" time or some delay (in seconds) probably do not need all the digits. To be specific, in RefPerSys objects are dumped in JSON and contain their modification time (a bit like in Linux filesystem), and that modification time is only precise to a centisecond. As another example, if a JSON object represent my physical properties in a health related application, it make absolutely no sense to dump my weight (in kilograms) with more than one digit after the decimal point (depending on the time of the day, my weight is about 84kg, but could be 84.5kg or 83.5 kg...). As a third example, a JSON object representing weather data does not need to record the measured temperature with more than a decidegree Celsius of precision: it make no sense to record in JSON that the temperature in Paris today is 8.567°C, dumping { "city": "Paris", "temp": 8.7 } is more than enough.

Notice that JSON_REAL_PRECISION(n) is a global thing. I am suggesting to make it specific to some registered attributes....

So I suggest to add a global hashtable of object attribute name dumping functions.

I am ready to implement that feature if there is a reasonable chance for it to be pushed upstream.

I am thinking of some additional function like void json_register_dump_attribute_flag(const char*attrname, size_t attrflag); and for the weather temperature example I would suggest calling json_register_dump_attribute_flag("temp", JSON_REAL_PRECISION(1));

Regards

Basile Starynkevitch basile@starynkevitch.net and basile.starynkevitch@cea.fr near Paris in France. Personal webpage: http://starynkevitch.net/Basile/index_en.html

akheron commented 2 years ago

Hi!

The idea of setting real precision based on the name of object keys is unfortunately not much better than setting it globally with JSON_REAL_PRECISION. What if there are many nested JSON objects and two of them have properties with the same name, but you want to apply precision to only one of them? What about support for numbers inside arrays? Etc.

A correct fix, in my opinion, is in the application side. It's pretty easy to construct a C function that rounds a given float to a certain number of decimal places:

double round_to(double value, unsigned int places) {
  double e = pow(10, places);
  return round(value * e) / e;
}

round_to(12.3456, 2)
/* 12.34 */

Just round the timestamps, weights etc. before encoding them in JSON, and you're done! Except...

There is a problem. Not all number are losslessly representable by floats, so for example 1.1 gets encoded as 1.1000000000000001 by Jansson. To fix this, David Gay's dtoa algorigthm could be used, as mentioned already as early as in https://github.com/akheron/jansson/issues/10#issuecomment-23690621. Unless I'm mistaken, the algorithm is available in https://github.com/jwiegley/gdtoa/blob/master/dtoa.c and could be incorporated in Jansson to replace the current sprintf("%.17g") based approach.