JSON String Formatter

Here’s some code I rehashed from some Google findings to pretty print JSON. Helps me with debugging and has worked pretty decently so far.

Consider it beerware licensed.

void beautifyJSON (String& source, int numSpaces)
{
    String result;
    auto cp = source.getCharPointer();

    const auto whitespace = String::repeatedString (" ", jlimit (0, 8, numSpaces));
    int level = 0;
    bool ignoreNext = false;
    bool inputString = false;

    auto appendWhitespace = [&]()
    {
        for (int i = level; --i >= 0;)
            result << whitespace;
    };

    auto c = cp.getAndAdvance();
    while (c != 0)
    {
        switch (c)
        {
            case 0:
            case '\r':
            case '\n':
            break;

            case '[':
            case '{':
                if (inputString)
                {
                    result << c;
                    break;
                }

                ++level;
                result << c << newLine;

                appendWhitespace();
            break;

            case ']':
            case '}':
                if (inputString)
                {
                    result << c;
                    break;
                }

                if (level != 0)
                    --level;

                result << newLine;
                appendWhitespace();
                result << c;
            break;

            case ',':
                if (inputString)
                {
                    result << ",";
                    break;
                }

                result << "," << newLine;
                appendWhitespace();
            break;

            case '\\':
                ignoreNext = ! ignoreNext;

                result << "\\";
            break;

            case '"':
                if (! ignoreNext)
                    inputString = ! inputString;

                result << "\"";
            break;

            case ' ':
                if (inputString)
                    result << " ";
            break;

            case ':':
                result << ":";

                if (! inputString)
                    result << " ";
            break;

            default:
                ignoreNext = false;
                result << c;
            break;
        }

        c = cp.getAndAdvance();
    }

    source = result.trim();
}
3 Likes

Can you give an example of its output?

I found myself this week wanting a JSON formatter that would vertically align a bunch of property definitions, but don’t really have time to go down that rabbit-hole…

Sure, here’s a minified example, and formatted for C++. (From https://support.oneskyapp.com/hc/en-us/articles/208047697-JSON-sample-files ):

String asdf { R"({"quiz":{"sport":{"q1":{"question":"Which one is correct team name in NBA?","options":["New York Bulls","Los Angeles Kings","Golden State Warriros","Huston Rocket"],"answer":"Huston Rocket"}},"maths":{"q1":{"question":"5 + 7 = ?","options":["10","11","12","13"],"answer":"12"},"q2":{"question":"12 - 8 = ?","options":["1","2","3","4"],"answer":"4"}}}})" };
beautifyJSON (asdf);
DBG (asdf);

The result from the output:

{
    "quiz": {
        "sport": {
            "q1": {
                "question": "Which one is correct team name in NBA?",
                "options": [
                    "New York Bulls",
                    "Los Angeles Kings",
                    "Golden State Warriros",
                    "Huston Rocket"
                ],
                "answer": "Huston Rocket"
            }
        },
        "maths": {
            "q1": {
                "question": "5 + 7 = ?",
                "options": [
                    "10",
                    "11",
                    "12",
                    "13"
                ],
                "answer": "12"
            },
            "q2": {
                "question": "12 - 8 = ?",
                "options": [
                    "1",
                    "2",
                    "3",
                    "4"
                ],
                "answer": "4"
            }
        }
    }
}

Get rid of those nasty escaped quotes… Since C++11:
String asdf { R"({"quiz":{"sport":{"q1":{"question":"Which one is correct team name in NBA?","options":["New York Bulls","Los Angeles Kings","Golden State Warriros","Huston Rocket"],"answer":"Huston Rocket"}},"maths":{"q1":{"question":"5 + 7 = ?","options":["10","11","12","13"],"answer":"12"},"q2":{"question":"12 - 8 = ?","options":["1","2","3","4"],"answer":"4"}}}})" };

3 Likes

Nice! That feature definitely flew by me. I’ll patch that up.