Reputation: 63
A key in any level of the json hierarchy, how can I find that key without knowing exact keys in the path?
Upvotes: 1
Views: 1760
Reputation: 8997
Generally, this can be solved with a recursive function (a function which calls itself). We first pass it the document's object, then check the object's keys. If no keys are found, we will apply the same function on the values of each key. If an array is passed, we should iterate through it.
QJsonValue findKey(const QString& key, const QJsonValue& value) {
if (value.isObject()) {
const QJsonObject obj = value.toObject();
if (obj.contains(key))
return obj.value(key); // return 'early' if object contains key
for (const auto& value : obj) {
QJsonValue recurse = findKey(key, value); // call itself, forwarding a value
if (!recurse.isNull())
return recurse; // value found, return 'early'
}
} else if (value.isArray()) {
for (const auto& value : value.toArray()) {
QJsonValue recurse = findKey(key, value);
if (!recurse.isNull())
return recurse;
}
}
return QJsonValue(); // base case: a null value
}
int main(int argc, char *argv[])
{
QFile file(":/res/scratch.json"); // json stored in a qrc with /res/ prefix
file.open(QIODevice::ReadOnly);
if (!file.isOpen()) {
qDebug() << "error: couldn't open scratch.json";
return 0;
}
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
qDebug() << "value:" << findKey("treasure", doc.object());
}
An example of a JSON file and relevant output:
scratch.json:
{
"deck": [
"first mate",
"sailor",
"john muir"
],
"cabin": [
{
"name": "lamp"
},
{
"name": "treasure chest",
"items": {
"diamonds": 3,
"silver": 5,
"gold": 10,
"safebox": {
"treasure": "shiny"
}
}
}
]
}
Output:
value: QJsonValue(string, "shiny")
Upvotes: 4