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

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 :-)

Related

How to read Json string starting with square brackets in it? [duplicate]

This question already has an answer here:
How to use boost::property_tree to parse JSON with array root
(1 answer)
Closed 2 years ago.
I am using c++ code to read json string to retrieve value based on specific key names. Example of my json response from web API is in array format like below.
[
{
"username": "123456",
"useraddress": "abc",
"data": [
{
"schedule": true,
"task": "abc",
"risk": "1",
}
],
"date": "0000-00-00"
}
]
Like the above format is the actual response. I have to retrieve date value using key "date".
My code snippet:
{
std::stringstream jsonString;
boost::property_tree::ptree pt;
jsonString << ws2s(Info).c_str();
boost::property_tree::read_json(jsonString, pt);
std::string date = pt.get<std::string>("date");
}
'Info' in above snippet is wsstring containing json response data.
I can able to retrieve "date" if [] square brackets are removed manually. Since it is array format, if I pass without removing brackets, read_json throws error.
Can somebody help this out?
Yeah. Boost Property Tree is a property tree library, not JSON.
You're in luck though, Boost has a JSON library now https://www.boost.org/doc/libs/1_75_0/libs/json/doc/html/index.html
Note: your input isn't valid JSON either, because JSON doesn't strictly allow trailing commas. You can enable them with an option in Boost JSON though:
Live On Compiler Explorer
#include <boost/json.hpp>
#include <iostream>
int main() {
std::string input = R"(
[
{
"username": "123456",
"useraddress": "abc",
"data": [
{
"schedule": true,
"task": "abc",
"risk": "1",
}
],
"date": "0000-00-00"
}
])";
boost::json::parse_options options;
options.allow_trailing_commas = true;
auto json = boost::json::parse(input, {}, options);
for (auto& el : json.as_array()) {
std::cout << el.at("date") << "\n";
}
}
Prints
"0000-00-00"

Fetching api with nlohmann/json

I want to use api with c++ and when I searched I found nlohmann/json library it looks really popular but no one talks about how to get the array that fetch function provides . How can I get the information from the api as variables in my cpp file
Didn’t quite understand your description, I assume you mean you want to get the JSON array? 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;
}

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;
}

How to delete nested json data using nlohmann 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;
}

How to search for the value of an object in a json file?

I'm trying to search for the value of an object in my json file.
If my json file is this:
[
{
"friendName": "Ann",
"birthday": "1990-04-19",
"favoriteColor": "Purple",
},
{
"friendName": "Max",
"birthday": "1993-10-07",
"favoriteColor": "Purple",
},
{
"friendName": "Bob",
"birthday": "1992-02-20",
"favoriteColor": "Red",
}
]
How would I be able to do something like (in pseudo):
if (object value is "Purple") {
print object value of friendName;
}
So that the end result would be
Ann
Max
I am using the json parser Json for Modern C++ (https://github.com/nlohmann/json). I'm new to C++ so I'm having difficulty understanding the README. I'm using Xcode (version 6.4)
I've tried using this:
// find an entry
if (o.find("foo") != o.end()) {
// there is an entry with key "foo"
}
But it doesn't seem to work. I know how to print the value of an object if I know its positon using this code:
std::cout << obj[0]["friendName"];
Which would result in:
Ann
Also, I'm also looking for a way to read the first part of a value. For example, if I wanted to list the names of people whose birthdays are during or after the year 1992, it would print:
Max
Bob
Any guidance would be appreciated!
Through the magic of C++11 (and a very well-designed library), the answer is almost identical to your pseudo-code:
for (const auto& obj : my_json) {
if (obj["favoriteColor"] == "Purple") {
std::cout << obj["friendName"] << std::endl;
}
}
prints
"Ann"
"Max"