6

Consider the following example for which my source is

    Json::Value root;
    root["id"]=0;
            Json::Value text;
            text["first"]="i";
            text["second"]="love";
            text["third"]="you";
    root["text"]=text;
    root["type"]="test";
    root["begin"]=1;
    root["end"]=1;
    Json::StyledWriter writer;
    string strJson=writer.write(root);
    cout<<"JSON WriteTest" << endl << strJson <<endl;

I thought I'd write the json fields in the order of the lines. Instead the result is:

JSON WriteTest
{
   "begin" : 1,
   "end" : 1,
   "id" : 0,
   "text" : {
      "first" : "i",
      "second" : "love",
      "third" : "you"
   },
   "type" : "test"
}

I want json format is

JSON WriteTest
{
   "id" : 0,
   "text" : {
      "first" : "i",
      "second" : "love",
      "third" : "you"
   },
   "type" : "test"
   "begin" : 1,
   "end" : 1,
}

How can I write a Json order?

1
  • 2
    The order should not matter to the writing or the reading applications. So you should correct these. Commented Jun 15, 2015 at 4:59

5 Answers 5

4

No, I don't think you can. JsonCpp keeps its values in a std::map<CZString, Value>, which is always sorted by the CZString comparison. So it doesn't know the original order you added items.

Sign up to request clarification or add additional context in comments.

Comments

3

This is my workaround to a get an ordered json output from jsoncpp

Json::Value root;
root["*1*id"]=0;
        Json::Value text;
        text["*1*first"]="i";
        text["*2*second"]="love";
        text["*3*third"]="you";
root["*2*text"]=text;
root["*3*type"]="test";
root["*4*begin"]=1;
root["*5*end"]=1;
Json::StyledWriter writer;
string resultString=writer.write(root);
resultString=ReplaceAll(resultString,"*1*", "");
resultString=ReplaceAll(resultString,"*2*", "");
resultString=ReplaceAll(resultString,"*3*", "");
resultString=ReplaceAll(resultString,"*4*", "");
resultString=ReplaceAll(resultString,"*5*", "");
cout<<"JSON WriteTest" << endl << resultString <<endl;

with RepleceAll function defined as this

std::string ReplaceAll(std::string str, const std::string& from, const std::string& to) {
        size_t start_pos = 0;
        while((start_pos = str.find(from, start_pos)) != std::string::npos) {
            str.replace(start_pos, from.length(), to);
            start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
        }
        return str;
    }

Comments

2

As mentioned by The Dark, JsonCpp keeps its values in a std::map<CZString, Value>, which is always sorted by the CZString comparison, without keeping track neither of the original order in which you added the items nor the desired order in the output.

But you can use this "hidden feature" in your benefit. I mean, you just need that the keys in the desired order follow the "natural" order of CZString. I have a method in my JSONCPP wrapper classes that do this. The quick'n'dirty code, converted to simple function, would be something like this:

std::string sortedStr(Json::Value & value, std::vector<std::string> sortKeys) 
{
    Json::Value sortedValue;  // The JSON object to store the new (sorted) hash
    char newKey[60]; // I use C expressions, modify to C++ if you like 
    // Build new sortedValue
    int i = 0;
    for (auto & key : sortKeys) {
        sprintf(newKey, "SORTEDKEY:%03d-%s", i++, key.c_str());
        sortedValue[newKey] = value[key];
    }
    // Write to string, should be sorted on primary keys
    Json::StyledWriter w;
    std::string result = w.write(sortedValue);
    // Remove aux. tags from primary keys 
    std::size_t pos = 0;       
    while ((pos = result.find("SORTEDKEY:", pos)) != std::string::npos) {
        result.erase(pos, 14);
    }
    return result;
}

To use it, just call:

std::string sortedObjStr = sortedValue(myValue, {"first", "second", "third", "fourth"});

Note that:

  • I use this for relatively small objects (configuration data).
  • I use the "tag" SORTEDKEY, since this is not going to appear anywhere in my data. Modify according to your needs.
  • I do not check that the keys used do exist. You can add this check.
  • You can use this also to generate a restricted, ordered subset of your original object.

Comments

1

I have a way can solve your problem. Would you like to try? My solution is that you use boost/property_tree/json_parser.hpp, the output is what format you want! About There is my code:

#include <boost/property_tree/json_parser.hpp>
#include <sstream>
#include <iostream>

using namespace std;
int main()
{
    boost::property_tree::ptree parser, child;
    parser.put("id", 0);
    child.put("first", "i");
    child.put("second", "love");
    child.put("third", "you");
    parser.put_child("text", child);
    parser.put("type", "test");
    parser.put("begin", 1);
    parser.put("end", 1);
    stringstream ss;
    boost::property_tree::json_parser::write_json(ss, parser);
    cout << ss.str() << endl;
    return 0;
}

Before run the codes, you should install boost 1.57. The codes run well in gcc 4.7, boost 1.57.The output is { "id" : 0, "text" : { "first" : "i", "second" : "love", "third" : "you" }, "type" : "test" "begin" : 1, "end" : 1, }. About boost::property_tree::ptree, you can click here. It used list<pair<key, ptree>> for saving data. So it saved unordered data, unless you called list.sort(). I hope this can help you.

4 Comments

What are the licensing of this?
Sorry, I do not know your meaning cleary. About boost::property_tree::ptree, you can click here.My guess is wrong, it uses list<pair<key, ptree>> for saving data.
About boost::property_tree::ptree, you can click here. It used list<pair<key, ptree>> for saving data. So it saved unordered data, unless you called list.sort().
The boost::property_tree::ptree's license is here
0

The key-value pairs in an object will always be sorted. Json arrays are not sorted, they consists of a series of values without keys. Objects, as named collections (arrays) of key-value pairs within brackets, in an array, will retain their positions, e.g.

{
"adressen" : [
  {
     "start" : {
        "ID" : 1,
        "key" : "2352KJ25",
        "lat" : 52.157225922529967,
        "lon" : 4.5298663828345527
     }
  },
  {
     "eind" : {
        "ID" : 2,
        "key" : "2352KJ25",
        "lat" : 52.157225922529967,
        "lon" : 4.5298663828345527
     }
  }
}

ID, key, lat, lon are sorted, but start and eind are in their original positions. So, at least your first, second, third could have been

Json::Value text(Json::arrayValue);
text.append("I");
text.append("love");
text.append("you");

No need for the tags first, second and third! Maybe this helps you to find a workaround.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.