How to delete nested json data using nlohmann c++ - c++

I have a below json data. I am using nlohmann json in C++.
{
"CompanyName": "XYZ Tech",
"Created": "2019-10-16T20:14:29Z",
"TxnId": "4509237",
"Tags": [
{
"ROIId": "Default",
"Time": 71,
"Tracker": "emp10"
},
{
"ROIId": "MC16",
"Time": 21,
"TrackerId": "emp10"
},
{
"ROIId": "Default",
"Time": 11,
"TrackerId": "emp11"
},
{
"ROIId": "MC18",
"Time": 10,
"TrackerId": "emp11"
}
],
"Type": "TxnData"
}
In above json data, inside Tags, we have data where the ROIId is Default. I want to delete it so that the data becomes:
{
"CompanyName": "XYZ Tech",
"Created": "2019-10-16T20:14:29Z",
"TxnId": "4509237",
"Tags": [
{
"ROIId": "MC16",
"Time": 21,
"TrackerId": "emp10"
},
{
"ROIId": "MC18",
"Time": 10,
"TrackerId": "emp11"
}
],
"Type": "TxnData"
}
How can I do it in c++. Thanks

I suggest iterating through the json::array stored in Tags and saving the Key of the matched elements. This way you can later validate the deletion and safely delete the elements.
Note that deleting is exactly like erasing with a STL vector - I prefer to delete from the end of the vector to avoid changing the keys while deleting multiple elements.
Here is a quick and dirty demo
And here is the code:
#include <iostream>
#include <vector>
#include "json3.6.1.hpp"
unsigned removeDefaultROIID(nlohmann::json& jsonObject, const std::string& value) {
std::vector<int> toremove;
//Loop through the `tags` json::array and create a vector of indexes to delete:
for (auto &it : jsonObject["Tags"].items()) {
//`.get<std::string>()` is the best way to make sure we are getting the value as std::string
if (it.value().at("ROIId").get<std::string>() == value)
toremove.push_back(stoi(it.key()));
}
//sort it before erase - we want to delete first biggest index:
std::sort(toremove.rbegin(), toremove.rend());
//delete using `.erase()` method:
for (int &it : toremove)
jsonObject["Tags"].erase(jsonObject["Tags"].begin() + it);
return toremove.size();
}
int main()
{
//Create the JSON object:
nlohmann::json jsonObject = R"({"CompanyName":"XYZ Tech","Created":"2019-10-16T20:14:29Z","TxnId":"4509237","Tags":[{"ROIId": "Default","Time": 71,"Tracker": "emp10"},{"ROIId":"MC16","Time": 21,"TrackerId": "emp10"},{"ROIId":"Default","Time":11,"TrackerId":"emp11"},{"ROIId":"MC18","Time": 10,"TrackerId":"emp11"}],"Type":"TxnData"})"_json;
std::cout << "JSON nested object value conditional erase:" << std::endl;
std::cout << "JSON object TAGS count - BEFORE deletion:" << jsonObject["Tags"].size() << std::endl;
//Call the method -> jlson is passed by ref
unsigned removed = removeDefaultROIID(jsonObject, "Default");
std::cout << "JSON object TAGS count - AFTER deletion:" << jsonObject["Tags"].size() << std::endl;
return 0;
}

Related

How to read a json obj created with the nlohmann::json lib

I'm getting a JSON string from a curl request, like this:
[
{
"name": "P309",
"path": "P309",
"sha": "b9dbfa7ceb9db3b73c84ff326a418bdd50c1b227",
"type": "file",
"_links": {
"self": "https://api.github.com/repos//files/contents/P309?ref=main",
"git": "https://api.github.com/repos//files/git/blobs/b9dbfdd50c1b227",
"html": "https://github.com//files/blob/main/P309"
}
},
{
"name": "P310",
"path": "P310",
"sha": "b9dbfa7ceb9db3b73c84ff326a418bdd50c1b227",
"_links": {
"self": "https://api.github.com/repos//files/contents/P309?ref=main",
"git": "https://api.github.com/repos//files/git/blobs/b9dbfdd50c1b227",
"html": "https://github.com//files/blob/main/P309"
}
},
]
How can I parse/read it using the nlohmann::json lib?
I've found this example:
/*
"emulators": [
{
"general_info": {
"dev_id": "0123456789"
}
}
]
*/
for(json& o : data["emulators"]) {
json& gi = o["general_info"];
std::cout << gi["dev_id"] << '\n';
}
My JSON being parsed doesn't have any 'title/header', I'm confused about how to read it.
I tried:
using json = nlohmann::json;
json data = json::parse(downloaded_data);
for(json& o : data[0]) {
auto git = o["git"].get<std::string>();
auto name = o["name"].get<std::string>();
}
git outputs the value correctly, however, when reading name it throws an exception.
This is the value of data in the debugger
and this, of o.
Can I get any help on this?

reading arrays of json objects with nlohmann c++ library

I am ok using this syntax with the nlohmann library
{
"key1": {"subKey1": "value11",
"subKey2": "value12"},
"key2": {"subKey1": "value21",
"subKey2": "value22"}
}
But I have a new file, which is valid json too (I checked) and is written this way, it is made of a single array of repetitive objects. My code will require to look through those objects and check values inside them individually:
[
{"key1": "value11",
"key2": "value12"},
{"key1": "value21",
"key2": "value22"}
]
I used to read my json files this way:
#include "json.hpp"
nlohmann::json topJson;
nlohmann::json subJson;
if(topJson.find(to_string("key1")) != topJson.end())
{
subJson = topJson["key1"];
entity.SetSubKeyOne(subJson["subKey1"]);
}
But this won't work with my new file syntax. How can I access these repetitive objects and tell nlohmann that my objects are inside an array? More precisely, how would I be able to reach (for example) "value22" with this file syntax?
Thanks!
You can try this:
std::string ss= R"(
{
"test-data":
[
{
"name": "tom",
"age": 11
},
{
"name": "jane",
"age": 12
}
]
}
)";
json myjson = json::parse(ss);
auto &students = myjson["test-data"];
for(auto &student : students) {
cout << "name=" << student["name"].get<std::string>() << endl;
}

Getting null values while saving json data in file using nlohmann json

I am using nlohmann json to create ans save some json values. But when I look at the file, I get null values in between the json. Below is how it looks like:
{
"Created": "2019-07-03T13:54:32Z",
"DataId": "BHI-201-U8",
"Data": [
{
"Name": "Andrew",
"Attended": "Yes"
},
{
"Name": "John",
"Attended": "Yes"
},
null, <-- unexpected null
{
"Name": "Ronny",
"Attended": "No"
},
null, <-- unexpected null
null, <-- unexpected null
{
"Name": "Mathew",
"Attended": "Yes"
}
],
"Type": "Person"
}
As you can see in the above json data, I am getting some unexpected null. Below is how I am saving it:
#include "nlohmann/json.hpp"
using nlohmann::json;
int main()
{
json outJson;
//some code
string outFile = "output.json";
for (const auto &data : trackedData->Detections())
{
//some code
outJson["Data"][data.id]["Name"] = data.name;
outJson["Data"][data.id]["Attended"] = data.status;
}
outJson["Created"] = created;
outJson["DataId"] = "BHI-201-U8";
outJson["Type"] = "Person";
std::ofstream output_file(outFile);
output_file << outJson.dump(4 , ' ', false);
output_file.close();
}
How can I remove these extra null from the code.
trackedData->Detections() returns a list of objects or structures and some of them are null-valued, hence nulls in the json. Try to do null-checking before adding data entry into json.
for (const auto &data : trackedData->Detections())
{
//some code
if (data != NULL)
{
outJson["Data"][data.id]["Name"] = data.name;
outJson["Data"][data.id]["Attended"] = data.status;
}
}

How to access element of JSON using Qt

I have this Json object and I want to access the "duration" and show it on console using Qt :
{
"kind": "youtube#videoListResponse",
"etag": "\"cbz3lIQ2N25AfwNr-BdxUVxJ_QY/brZ0pmrmXldPPKpGPRM-8I4dDFQ\"",
"pageInfo": {
"totalResults": 1,
"resultsPerPage": 1
},
"items": [
{
"kind": "youtube#video",
"etag": "\"cbz3lIQ2N25AfwNr-BdxUVxJ_QY/PkTW6UN9MH0O2kDApjC3penIiKs\"",
"id": "WkC18w6Ys7Y",
"contentDetails": {
"duration": "PT58M21S",
"dimension": "2d",
"definition": "hd",
"caption": "false",
"licensedContent": true,
"projection": "rectangular"
}
}
]
}
And my Qt code is this :
{
QJsonDocument jsonResponse = QJsonDocument::fromJson(message);
results = jsonResponse.object();
QJsonValue v1 = results.value("items");
qDebug() << "v1 = " << v1;
QJsonValue v2 = v1.toObject().value("contentDetails");
qDebug() <<"v2 = " << v2;
QString v3 = v2.toObject().value("duration").toString();
qDebug() << "v3 = " << v3;
}
However my output is :
v1 = QJsonValue(array, QJsonArray([{"contentDetails":{"caption":"false","definition":"hd","dimension":"2d","duration":"PT58M21S","licensedContent":true,"projection":"rectangular"},"etag":"\"cbz3lIQ2N25AfwNr-BdxUVxJ_QY/PkTW6UN9MH0O2kDApjC3penIiKs\"","id":"WkC18w6Ys7Y","kind":"youtube#video"}]))
v2 = QJsonValue(undefined)
v3 = ""
So v1 is fine but v2 becomes undefined.What am I doing wrong and how can I access the "duration" item correctly?
The direct answer as follows:
// Read the file which has the JSON object.
QFile file("jsonString.json");
if(!file.open(QFile::ReadOnly)){
qDebug()<< "Error, Cannot open the file.";
return false;
}
QJsonDocument jsonDoc = QJsonDocument::fromJson(file.readAll());
qDebug()<< jsonDoc.object().value("items").toArray()[0].toObject().value("contentDetails").toObject().value("duration").toString();
The result:
PT58M21S
items is a list, so calling toObject() on it just returns the default value. According to the documentation:
Converts the value to an object and returns it.
If type() is not Object, the defaultValue will be returned.
You need to be calling toArray() on it, which will convert it to a QJsonArray. From there you can take the first item from the array using a variety of methods, or iterate over the array if that makes more sense for your schema.

How can I parse JSON arrays with C++ Boost?

I have a file containing some JSON content that looks like:
{
"frame":
{
"id": "0",
"points":
[
[ "0.883", "0.553", "0" ],
[ "0.441", "0.889", "0" ],
]
},
"frame":
...
}
How do I parse the values of the double array using C++ and Boost ptree?
Use the iterators, Luke.
First , you have to parse the file:
boost::property_tree::ptree doc;
boost::property_tree::read_json("input_file.json", doc);
... now, because it seems you have multiple "frame" keys in the top level dictionary you must iterate over them:
BOOST_FOREACH (boost::property_tree::ptree::value_type& framePair, doc) {
// Now framePair.first == "frame" and framePair.second is the subtree frame dictionary
}
Iterating over the rows and columns is the same:
BOOST_FOREACH (boost::property_tree::ptree::value_type& rowPair, frame.get_child("points")) {
// rowPair.first == ""
BOOST_FOREACH (boost::property_tree::ptree::value_type& itemPair, rowPair.second) {
cout << itemPair.second.get_value<std::string>() << " ";
}
cout << endl;
}
I didn't test the code, but the idea will work :-)