How to add ellements in QJsonArray? - c++

Good day. In my QT aplication, there is a need to store the value of structures of the same type in a JSON dictionary.
Values should be possible to add, read, change, delete. I know about the JSON Save Game Example article, I tried to figure it out for a long time, I didn’t come to anything, I also surfed the forums with the same result.
The main problem is this:
Let's say I have the following structure:
struct Laptop{
std::string name;
int price;
int year;
};
And I want to store an array of such structures in a JSON dictionary. I am using the following code:
//filling structure
Laptop Ltemp = {"some name" , 1000, 2022};
//adding structure to JSON object
QJsonObject g;
g.insert("name", Ltemp.name.c_str());
g.insert("price", Ltemp.price);
g.insert("year", Gtemp.year);
//open and wtritingmy JSON
QFile file("path/to/myfile.json");
QByteArray jsonData = file.readAll();
QJsonDocument document = QJsonDocument::fromJson(jsonData);
QJsonObject object = document.object();
QJsonValue value = object.value("mydata");
QJsonArray myArray= value.toArray();
myArray.removeAt(0);
myArray.append(g);
object.insert("mydata", myArray);
document.setObject(object);
//write to file
file.write(document.toJson());
file.close();
{
Expecting at the same time that when you re-apply the code, the data of the structure will be added to the same array, the key of which is "mydata", but in the end I have this:
"mydata": [
{
"name": "some name",
"price": 1000,
"year": 2022
}
],
"mydata": [
{
"name": "some name",
"price": 1000,
"year": 2022
}
]
}
instead of
"mydata": [
{
"name": "some name",
"price": 1000,
"year": 2022
},
{
"name": "some name",
"price": 1000,
"year": 2022
}
]

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"

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

Creating a json database with user input

I need to create my .json array to look like this:
{
"airports": [{
"address": "Horley, Gatwick RH6 0NP, UK",
"city": "London",
"shortVersion": "LGW"
},
{
"address": "Marupe, LV-1053",
"city": "Riga",
"shortVersion": "RIX"
}
]
}
But I have it looking right now like this:
{
"airports": {
"(LGW)": {
"address": "Horley, Gatwick RH6 0NP, UK",
"city": "London",
"shortVersion": "(LGW)"
},
"(RIX)": {
"address": "Marupe, LV-1053",
"city": "Riga",
"shortVersion": "(RIX)"
}
}
}
The code I have for user input right now is this:
airports["airports"][inputShortVersion]["shortVersion"] = inputShortVersion;
airports["airports"][inputShortVersion]["city"] = inputCity;
airports["airports"][inputShortVersion]["address"] = inputAddress;
I've searched for a whole day on how to do this, but closest I got to was where it does create the above array but after input it overwrites the last airport data.
I'm using nlohmann json library.
You have a sequence container in your desired output, but associative container in your code.
Try something like
json inputAirport;
inputAirport["shortVersion"] = inputShortVersion;
inputAirport["city"] = inputCity;
inputAirport["address"] = inputAddress;
airports["airports"].push_back(inputAirport);
Apparently, you are creating a json object instead of a json array. To get an array, you could try along the lines of the following:
airports["airports"] = nlohmann::json::array()
new_airport = nlohmann::json::object()
new_airport["shortVersion"] = inputShortVersion;
new_airport["city"] = inputCity;
new_airport["address"] = inputAddress;
airports["airports"].emplace_back(new_airport);
This can be written shorter with braced initalizer lists at the cost of readability:
airports["airports"] = nlohmann::json::array()
airports["airports"].emplace_back(
{
{"shortVersion", inputShortVersion},
{"city", inputCity},
{"address", inputAddress}
});

How to get JSONobject from JSONArray in postman

I am trying to automize a registration scenario in postman using test scripts
I have the following JsonArray as a response:
[
{
"id": 1,
"name": "user_A",
"cntkp": "martin",
"company": "kreativ",
"tel": "12345678",
"email": "user_A#gmail.com"
"street": "str. 0001",
"city": "DEF",
}
......
......
......
{
"id": 4,
"name": "user_B",
"cntkp": "martin",
"company": "kreativ",
"tel": "12345678",
"email": "user_B#gmail.com"
"street": "str. 0002",
"city": "NJ",
}
......
......
......
{
"id": 10,
"name": "User_C",
"cntkp": "martin",
"company": "kreativ",
"tel": "12345678",
"email": "user_C#gmail.com"
"street": "str. 0003",
"city": "ABC",
}
......
]
the array length can be dynamic and changed (in this sample is 10) and want to find the object with special email (somewhere in the array) and then get the ID from that object and make the assertion based on JsonData from this object (catch elements e.g. check name).
how can I do that?
thanks for the support.
I send a GETrequest to get all Data from Registration DB.
as response I get a JsonArray
from Json Array I need the specific Object for the assertion (e.g. object with email user_B in sample) .
I know my Email address and base on it I have to findout the ID from Object .
I can do it when I know which ID is my ID but in case it is dynamic I don't know how to search an array for it in postman to get ID
For example, to assert the company name
pm.expect(jsonData[0].company).to.equal(pm.environment.get("regDB_new_company"))
but if I dont know the ID ( only know my email) I have first to find out the ID of Object then I can asser it.
e.g.
in this case first, find the object with email "user_B#gmail.com"
then from that object get ID element (in this case 4)
then I want to assert for all data from the object
Thanks Danny, I found the solution
var arr = pm.response.json()
for(i = 0; i < arr.length; i++) {
if (arr[i].email == "userB#gmail.com") {
pm.environment.set("personID", arr[i].id)
}
}

Get the name for Apache Avro's generic record field?

I'm using Avro in C++ using generic data objects.
Assuming the schema is the same as in the examples:
{
"type": "record",
"name": "cpx",
"fields" : [
{"name": "re", "type": "double"},
{"name": "im", "type" : "double"}
]
}
I can get the GenericRecord' andGenericDatum` like this:
const avro::GenericRecord& r = datum.value<avro::GenericRecord>();
const avro::GenericDatum& f0 = r.fieldAt(0);
std::string field0name = ???; // should be "re"
How do I get the field f0's name that is specified in the schema? In this example, it should return "re".
First grab the schema pointer and then access the name:
std::string field0name = r.schema()->nameAt(0);