Open fedormsv opened 4 years ago
Relate discussion : https://github.com/open-source-parsers/jsoncpp/issues/237
Can someone please point out exactly where in the json code the fields are being sorted alphabetically? And what changes must be made to stop this from happening?
I want to read in a json file, and write it out again, without making any edits or changes. Field order must be preserved.
It's std::map container used to store fields that sorts them. To solve the issue you need another container. Take care: this map is also used for storing arrays elements, and there is a requrement to get an element with max key.
I solved the issue in our project creating custom container, something like LinkedMap.
Can someone please point out exactly where in the json code the fields are being sorted alphabetically?
It's implicated by this typedef for the Json::Value::ObjectValues map type:
typedef std::map<CZString, Value> ObjectValues;
And std::map
uses sorted keys. We currently have no option to track insertion order of the keys within a Json::Value
.
It would be neat to let the Reader emit SAX parse events instead of just building up a Json::Value and returning it when it's finished. Then the parse and the storage of its results can be decoupled for special cases like yours. But that's perhaps a job for a different json library.
Thanks for the reply. I haven't used std::map much to realize it's sorting keys while inserting them.
Is jsoncpp dependent on this sorting behavior in any way?
Because I'm willing to make a compromise. I can use std::map, but only if I can change the rules. I want to give priority to a small list of keywords, so they are always sorted at the top, while everything else is sorted as usual. So, I would like to able to pass std::map my own comparison function.
Would that cause any problems?
As I mentioned, it makes sense for arrays. More precisely: Value:size() method depends on the fact map is sorted and can give max key by accessing element before end() iterator. It allows array to keep only non-null entries and still easily get its size.
I must be using an older version of jsoncpp. I can't find a method called max_key. I use an older compiler that doesn't require C+11.
Found std::map, it's hiding in value.h: typedef std::map<CZString, Value> ObjectValues;
I still would like to know if I can pass it my own comparsion function without breaking anything.
Ok, I tried a couple of things:
//////////////////////////////////////
// this works
typedef std::map<CZString, Value, std::less
////////////////////////////////////// // this works struct cmp { bool operator()(const CZString l, const CZString r) const { return (l < r); } }; typedef std::map<CZString, Value, cmp> ObjectValues;
////////////////////////////////////// // this works
struct cmp { bool operator()(const CZString l, const CZString r) const {
const char *a = (const char *)l.c_str();
const char *b = (const char *)r.c_str();
if(a && b) {
return (std::strcmp(a, b) < 0);
}
return (l.index() < r.index());
}
}; typedef std::map<CZString, Value, cmp> ObjectValues;
(please ignore bad formatting, code is correct, github stripped some symbols from it)
Which all follow the std::less rule, but if I try to change the ordering, it breaks, and the file only partially loads, with broken arrays.
I'm guessing it has something to do with this index() member? Is it not possible to change the sorted order of map elements without breaking anything?
thanks, but if it's written for C+11, I won't be able to compile it with my old compiler.
nothing specific, except move constructor and assignment probably
You need a new compiler. Just bite the bullet. 2011 was 9 years ago.
If I can get custom field ordering working, I just might. :)
Just have a look on my fork, branch named "non_sorting"
Only compiled using c++14
Fixed for c++ 11 now
That is great, I got it compiled with VS 2015 C++, and it was seamless. Perfectly preserved order.
Thank you very much!
@fedormsv, Good and necessary sorting function, you must try to transfer completely to the master branch via PR.
@fedormsv Thanks for the version. Another recommendation to add to the master branch.
For reference (mine as well as others) -
git clone https://github.com/fedormsv/jsoncpp.git
cd jsoncpp
git branch -a
git checkout remotes/origin/non_sorting
Now, I used the amalgamated version
python amalgamate.py
Also copy historic_map.h into the json/ dir as its now needed.
Alphanumeric sorting would be useful too
The sorting/non-sorting option should be a STD feature in the main branch.
To use json files in a context where human readability makes sense, order of the fields insertion can make sense. As jsoncpp is sorting them alphabetically, it becomes hard to read the file and find related fields in ddifferent ends of the object. For example Json::Value root; root["name"] = "Test;" root["host"] = "127.0.0.1"; root["port"] = 80;
would be nice to have printed as
{ "name" : "Test, "host" : "127.0.0.1", "port" : 80 }
and not as
{ "host" : "127.0.0.1", "name" : "Test, "port" : 80 }
I actually succeeded to have this feature by replacing a container used by Json::Value with a custom one.