"\n" in std::string is printed as "\n" itself when writing to a JSON file using RapidJSON

108 Views Asked by At

I have a JSON string with \n characters in the middle. When I use cout to test printing the string, below is the output I get, which is expected.

I am constructing the string with something like this:

string jsonStr = "{\n Enable : ";
jsonStr += "1\n";
jsonStr += "test : ";
jsonStr += "hello\n";
jsonStr += "}\n";

I print the jsonStr with cout << jsonStr, and it prints the string as expected:

{
    Enable  : 1
    test : hello
}

But when I try to write this string to a JSON file using pretty writer, it adds the \n as well to the JSON member values.

I can't figure out how to get rid of this \n. In my Google searching, I found some solution to try appending \\n instead of \n to the string, but it still didn't work. The JSON file had \\n added to the string instead of \n.

How can I fix this?

Below is the code I've tried:

void write_to_module_json_file(const string jsonStr, const string moduleName) {

    string jsonFile = getConfigName(moduleName)+".json";

    Document d(kObjectType);
    Value data(kObjectType);
    Value value;
    value.SetString(jsonStr.c_str(), d.GetAllocator());
    data.AddMember(rapidjson::StringRef(getConfigName(moduleName).c_str()), value,d.GetAllocator());
    d.AddMember("config", data, d.GetAllocator());

    FILE* fp = fopen(jsonFile.c_str(), "wb"); 
    char writeBuffer[65536];
    FileWriteStream os(fp, writeBuffer, sizeof(writeBuffer));

    PrettyWriter<FileWriteStream> writer(os);
    writer.SetIndent('\t',1);
    d.Accept(writer);
    fclose(fp);
}

The JSON file has the below content:

{
    "config": {
        "xxx": "{\n    Enable  : 1\n    test : hello\n}\n"
    }
}

My expectation is to have the JSON file content as:

{
    "config": 
     {
        "xxx": 
        {
            Enable  : 1,
            test : hello
       }
    }
}
1

There are 1 best solutions below

0
Remy Lebeau On

Per comments:

Your jsonStr doesn't contain valid JSON, because it's missing quotes around object keys and strings. But that doesn't matter to RapidJSON, because you're telling it to add jsonStr as a string value, not a JSON snippet.

Sebastian Redl

it is also missing a comma between the two fields.

Remy Lebeau

Your jsonStr content is malformed as JSON, but that doesn't matter since you are assigning the content of jsonStr as-is as a single string value xxx in your final JSON document. But the C++ '\n' character is not allowed to appear as-is in a JSON string value, a JSON string value cannot span multiple lines.

That is why the '\n' character in your std::string gets escaped as "\n" in the final JSON.

To get the JSON result you are looking for, you need to parse your jsonStr as its own JSON value first, and then add that value to your final document, eg:

// NOTE THE EXTRA QUOTES AND COMMA TO MAKE THIS LEGAL JSON...
string jsonStr = "{\n \"Enable\" : ";
jsonStr += "1,\n";
jsonStr += "\"test\" : ";
jsonStr += "\"hello\"\n";
jsonStr += "}\n";
void write_to_module_json_file(const string jsonStr, const string moduleName) {

    string configName = getConfigName(moduleName);
    string jsonFile = configName + ".json";

    Document d(kObjectType);
    Value data(kObjectType);

    /* DON'T DO THIS!!!
    Value value;
    value.SetString(jsonStr.c_str(), d.GetAllocator());
    data.AddMember(configName.c_str(), value, d.GetAllocator());
    */
    // DO THIS INSTEAD...
    Document doc;
    doc.Parse(jsonStr.c_str());
    data.AddMember(configName.c_str(), doc, d.GetAllocator());
    //

    d.AddMember("config", data, d.GetAllocator());

    FILE* fp = fopen(jsonFile.c_str(), "wb"); 
    char writeBuffer[65536];
    FileWriteStream os(fp, writeBuffer, sizeof(writeBuffer));

    PrettyWriter<FileWriteStream> writer(os);
    writer.SetIndent('\t',1);
    d.Accept(writer);
    fclose(fp);
}