Baklap4 Baklap4 - 5 months ago 17
JSON Question

Creating JSON object from language file

I'm having a translation file which looks like this:

#: this is just some comment
msgid ""
"this is a line.\n"
"this is a newline.\n"
"this is another newLine".
msgstr ""
"this can be filled in.\n"
"or left blank."
#: just another comment
msgid "Pizza"
msgstr ""


As you can see
msgid
can be multiline or singlelined. Same goes for
msgstr
.

All my translation files looks like this. How would i create a json object containing two keys like this using the above data example:

[
{
"msgid": "this is a line.\nthis is a newline.\nthis is another newLine.",
"msgstr": "this can be filled in.\n or left blank."
},
{
"msgid": "Pizza",
"msgstr": ""
}
]


I have access to a json libary which i know how to use. I'm struggling with the for(each) loop looping through the data.

At the moment i have this piece of code:

std::ifstream input(findFile("language.po"));
Json::Value jsonRoot = Json:arrayValue;
for( std::string line; getline( input, line ); )
{
Json::Value Translation = Json::objectValue;
if(line.find("msgid") == 0) {
//messageId found
Translation["msgid"] = line;
} else if(line.find("msgstr") == 0) {
//translated string was found
Translation["msgstr"] = line;
}
jsonRoot.append(Translation);
}


Yet this creates a new json array for every line which i do not want.

At this moment the current output (not tested) should be like this:

[
{
"msgid": ""
},
{
"msgstr": ""
},
{
"msgid": "Pizza"
},
{
"msgstr": ""
}
]

Answer

Your loop is adding each line to the array, regardless of the content of each line. What you need is a state machine so you only add completed objects to the array, you need to append continuation lines to previous lines until you reach the next field start, and you need to parse the lines to remove the line prefixes and quotes.

Try something more like this:

std::ifstream input(findFile("language.po"));

std::string msgid, msgstr;
std::string *field = NULL;
std::string::size_type start, end;

Json::Value jsonRoot = Json:arrayValue;

for( std::string line; std::getline( input, line ); )
{
    if (line.compare(0, 1, "#") == 0)
        continue;

    if (line.compare(0, 6, "msgid ") == 0)
    {
        if (!msgid.empty())
        {
            Json::Value Translation = Json::objectValue;
            Translation["msgid"] = msgid;
            Translation["msgstr"] = msgstr;
            jsonRoot.append(Translation);
        }

        msgid.clear();
        msgstr.clear();
        field = &msgid;
        start = 6;
    }
    else if (!field)
    {
        continue;
    }
    else if (line.compare(0, 7, "msgstr ") == 0)
    {
        field = &msgstr;
        start = 7;
    }
    else
    {
        start = 0;
    }

    start = line.find('\"', start);
    if (start == std::string::npos)
        continue;

    ++start;
    end = line.find('\"', start);
    if (end != std::string::npos)
        *field += line.substr(start, end-start);
    else
        *field += line.substr(start);
}

if (!msgid.empty())
{
    Json::Value Translation = Json::objectValue;
    Translation["msgid"] = msgid;
    Translation["msgstr"] = msgstr;
    jsonRoot.append(Translation);
}