I have a vector of key names, how do I create a json of these nested keys, such that it's like:
std::vector<std::string> keys = {"a", "b", "c"};
json myJson = createJson (keys);
the resulting json I want
{
"a" : {
"b" : {
"c" : {
}
}
}
}
and then after that, I want to be able to modify the deepest layer of myjson later in code, equivalent to:
myJson["a"]["b"]["c"].merge_patch(newJson1)
myJson["a"]["b"]["c"].merge_patch(newJson2)
However, the size of my key vector is variable, so I can't hardcode the ["a"]["b"]["c"]
part, I basically need some way to for loop through each key until I reach the end, and then do my update on that last element.
So far I solved createJson by looping through the keys in reverse and just creating new jsons, but this feels very inefficient as it looks like I'm creating a bunch of new jsons and a lot of copys:
json createJson (const std::vector<std::string> &keys) {
json j = json::value_t::object;
for (auto it = keys.rbegin(); it != keys.rend(); it++) {
json temp;
temp[*it] = j;
j = temp;
}
return j;
}
But now I don't have access to the deepest layer of the json anymore. What I then did is:
json createJson (const std::vector<std::string> &keys, json & j) {
for (auto it = keys.rbegin(); it != keys.rend(); it++) {
json temp;
temp[*it] = j;
j = temp;
}
}
json j;
createJson(newJson1);
createJson(newJson2);
j.merge_patch(newJson1);
j.merge_patch(newJson2);
Which works, but seems kind of dumb because now instead of just modifying the deepest json nest, merge_patch is merging across all the keys. Is there a better way to do this? Maybe my createJson should also return some pointer to the last nesting location somehow?
This implementation of createJson
might be a bit more efficient:
nlohmann::json createJson(const std::vector<std::string>& keys)
{
nlohmann::json root;
nlohmann::json* it = &root;
for (auto& key : keys)
{
it = &((*it)[key]);
}
*it = nlohmann::json({});
return root;
}
If you want access to the last created element you could just return it from createJson
, note that in order for the pointer to remain valid we must pass in the root element otherwise returning it from the function will invalidate the pointer:
nlohmann::json* createJson(nlohmann::json& root, const std::vector<std::string>& keys)
{
nlohmann::json* it = &root;
for (auto& key : keys)
{
it = &((*it)[key]);
}
*it = nlohmann::json({});
return it;
}
Then you can do:
nlohmann::json myJson;
auto it = createJson(myJson, keys);
it->merge_patch(newJson1);