Flatten multidimensional nested Qt Json structure like QJsonValue / QJsonObject / QJsonArray

106 Views Asked by At

Seeking a way of flattening a multidimensional nested QJsonValue containing all 6 basic data types (object, array, bool, double, String, Null).

Simple example for the purpose of understanding...Input:

{
    "date": 1681693886,
    "online": true,
    "none": null,
    "list": {
        "arr": [
            60,
            100,
            100,
            100,
            100,
            100
        ],
        "multiArr": [
            ["hi", "my", "name"],
            ["is", "unknown"],
            [{"first": 0}, {"last": 100}]
        ],
        "num": 60
    }
}

And this should be the expected output:

key = "date",                     value = "1.68169e+09"
key = "list.arr.0",               value = "60"
key = "list.arr.1",               value = "100"
key = "list.arr.2",               value = "100"
key = "list.arr.3",               value = "100"
key = "list.arr.4",               value = "100"
key = "list.arr.5",               value = "100"
key = "list.multiArr.0.0",        value = "hi"
key = "list.multiArr.0.1",        value = "my"
key = "list.multiArr.0.2",        value = "name"
key = "list.multiArr.1.0",        value = "is"
key = "list.multiArr.1.1",        value = "unknown"
key = "list.multiArr.2.0.first",  value = "0"
key = "list.multiArr.2.1.last",   value = "100"
key = "list.num",                 value = "60"
key = "none",                     value = "null"
key = "online",                   value = "true"
1

There are 1 best solutions below

0
On

a recursive solution:

...
include ...
...

void flattenJson(QJsonValue jsonVal, QString aggregatedKey = "")
{
    auto dryFx = [&](auto& key, auto& value)
    {
        const QString delimiter = ".";
        auto nKey = aggregatedKey + delimiter + key;
        if(nKey.at(0) == delimiter)
            nKey.remove(0, 1);

        if(value.isObject() || value.isArray())
            flattenJson(value, nKey);
        else
        {
            QString nVal;
            if(value.isString())
                nVal = value.toString();
            else if(value.isBool())
                nVal = value.toBool() ? "true" : "false";
            else if(value.isDouble())
                nVal = QString::number(value.toDouble());
            else if(value.isNull())
                nVal = "null";

            qInfo().nospace() << "key = " << nKey << ", value = " << nVal;
        }
    };

    if(jsonVal.isArray())
    {
        const auto json_arr = jsonVal.toArray();
        for(auto it = json_arr.constBegin(); it != json_arr.constEnd(); ++it)
        {
            const auto key = QString::number((it - json_arr.constBegin()));
            const auto value = *it;
            dryFx(key, value);
        }
    }

    if(jsonVal.isObject())
    {
        const auto json_obj = jsonVal.toObject();
        for(auto it = json_obj.constBegin(); it != json_obj.constEnd(); ++it)
        {
            const auto key = it.key();
            const auto value = it.value();
            dryFx(key, value);
        }
    }
}

int main() 
{
    QFile file;
    file.setFileName("/pathToJson");
    file.open(QIODevice::ReadOnly | QIODevice::Text);
    QString val = file.readAll();
    file.close();
    QJsonDocument jsonDoc = QJsonDocument::fromJson(val.toUtf8());
    flattenJson(jsonDoc.object());
    return 0;
}