RapidJSON library getting value without name field - c++

We got json reply similar to following from certain partner's api.
[
{ "firstName":"John" , "lastName":"Doe" },
{ "firstName":"Anna" , "lastName":"Smith" },
{ "firstName":"Peter" , "lastName": "Jones" }
]
when we tried to parse through rapidjson lib, parse didn't return any error, but we are not sure how to get value from document without the name field on the array. Anyone has any idea to deal with it?

std::string s("[ { \"firstName\":\"John\" , \"lastName\":\"Doe\" }, "
" { \"firstName\":\"Anna\" , \"lastName\":\"Smith\" }, "
" { \"firstName\":\"Peter\" , \"lastName\": \"Jones\" } ]");
rapidjson::Document doc;
doc.Parse<0>(s.c_str());
for (rapidjson::SizeType i = 0; i < doc.Size(); i++)
printf("\n%u: %s %s", i + 1, doc[i]["firstName"].GetString(), doc[i]["lastName"].GetString());

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?

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

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 to create/read/write JSON files in Qt5

Qt5 has a new JSON parser and I want to use it. The problem is that it isn't too clear about what the functions do in layman's terms and how to write code with it. That or I could be reading it wrong.
I want to know the code on creating a JSON file in Qt5 and what "encapsulates" mean.
Example: Read json from file
/* test.json */
{
"appDesc": {
"description": "SomeDescription",
"message": "SomeMessage"
},
"appName": {
"description": "Home",
"message": "Welcome",
"imp":["awesome","best","good"]
}
}
void readJson()
{
QString val;
QFile file;
file.setFileName("test.json");
file.open(QIODevice::ReadOnly | QIODevice::Text);
val = file.readAll();
file.close();
qWarning() << val;
QJsonDocument d = QJsonDocument::fromJson(val.toUtf8());
QJsonObject sett2 = d.object();
QJsonValue value = sett2.value(QString("appName"));
qWarning() << value;
QJsonObject item = value.toObject();
qWarning() << tr("QJsonObject of description: ") << item;
/* in case of string value get value and convert into string*/
qWarning() << tr("QJsonObject[appName] of description: ") << item["description"];
QJsonValue subobj = item["description"];
qWarning() << subobj.toString();
/* in case of array get array and convert into string*/
qWarning() << tr("QJsonObject[appName] of value: ") << item["imp"];
QJsonArray test = item["imp"].toArray();
qWarning() << test[1].toString();
}
OUTPUT
QJsonValue(object, QJsonObject({"description": "Home","imp": ["awesome","best","good"],"message": "YouTube"}) )
"QJsonObject of description: " QJsonObject({"description": "Home","imp": ["awesome","best","good"],"message": "YouTube"})
"QJsonObject[appName] of description: " QJsonValue(string, "Home")
"Home"
"QJsonObject[appName] of value: " QJsonValue(array, QJsonArray(["awesome","best","good"]) )
"best"
Example: Read json from string
Assign json to string as below and use the readJson() function shown before:
val =
' {
"appDesc": {
"description": "SomeDescription",
"message": "SomeMessage"
},
"appName": {
"description": "Home",
"message": "Welcome",
"imp":["awesome","best","good"]
}
}';
OUTPUT
QJsonValue(object, QJsonObject({"description": "Home","imp": ["awesome","best","good"],"message": "YouTube"}) )
"QJsonObject of description: " QJsonObject({"description": "Home","imp": ["awesome","best","good"],"message": "YouTube"})
"QJsonObject[appName] of description: " QJsonValue(string, "Home")
"Home"
"QJsonObject[appName] of value: " QJsonValue(array, QJsonArray(["awesome","best","good"]) )
"best"
JSON under QT is actually quite pleasant - I was surprised. This is an example of how to create a JSON output with some structure.
Forgive me for not explaining what the fields all mean - it is a Ham Radio processing output script.
This is the QT C++ Code
void CabrilloReader::JsonOutputMapper()
{
QFile file(QDir::homePath() + "/1.json");
if(!file.open(QIODevice::ReadWrite)) {
qDebug() << "File open error";
} else {
qDebug() <<"JSONTest2 File open!";
}
// Clear the original content in the file
file.resize(0);
// Add a value using QJsonArray and write to the file
QJsonArray jsonArray;
for(int i = 0; i < 10; i++) {
QJsonObject jsonObject;
CabrilloRecord *rec= QSOs.at(i);
jsonObject.insert("Date", rec->getWhen().toString());
jsonObject.insert("Band", rec->getBand().toStr());
QJsonObject jsonSenderLatObject;
jsonSenderLatObject.insert("Lat",rec->getSender()->fLat);
jsonSenderLatObject.insert("Lon",rec->getSender()->fLon);
jsonSenderLatObject.insert("Sender",rec->getSender_call());
QJsonObject jsonReceiverLatObject;
jsonReceiverLatObject.insert("Lat",rec->getReceiver()->fLat);
jsonReceiverLatObject.insert("Lon",rec->getReceiver()->fLon);
jsonReceiverLatObject.insert("Receiver",rec->getReceiver_call());
jsonObject.insert("Receiver",jsonReceiverLatObject);
jsonObject.insert("Sender",jsonSenderLatObject);
jsonArray.append(jsonObject);
QThread::sleep(2);
}
QJsonObject jsonObject;
jsonObject.insert("number", jsonArray.size());
jsonArray.append(jsonObject);
QJsonDocument jsonDoc;
jsonDoc.setArray(jsonArray);
file.write(jsonDoc.toJson());
file.close();
qDebug() << "Write to file";
}
It takes an internal QT Structure (a List of pointers to a CabrilloRecord object ... which you just ignore) and extracts some fields. These fields are then output in a nested JSON format which looks like this.
[
{
"Band": "20",
"Date": "Sat Jul 10 12:00:00 2021",
"Receiver": {
"Lat": 36.400001525878906,
"Lon": 138.3800048828125,
"Receiver": "8N3HQ "
},
"Sender": {
"Lat": 13,
"Lon": 122,
"Sender": "DX0HQ "
}
},
{
"Band": "20",
"Date": "Sat Jul 10 12:01:00 2021",
"Receiver": {
"Lat": 36.400001525878906,
"Lon": 138.3800048828125,
"Receiver": "JA1CJP "
},
"Sender": {
"Lat": 13,
"Lon": 122,
"Sender": "DX0HQ "
}
}]
I hope this speeds up someone else's progression on this topic.
Sadly, many JSON C++ libraries have APIs that are non trivial to use, while JSON was intended to be easy to use.
So I tried jsoncpp from the gSOAP tools on the JSON doc shown in one of the answers above and this is the code generated with jsoncpp to construct a JSON object in C++ which is then written in JSON format to std::cout:
value x(ctx);
x["appDesc"]["description"] = "SomeDescription";
x["appDesc"]["message"] = "SomeMessage";
x["appName"]["description"] = "Home";
x["appName"]["message"] = "Welcome";
x["appName"]["imp"][0] = "awesome";
x["appName"]["imp"][1] = "best";
x["appName"]["imp"][2] = "good";
std::cout << x << std::endl;
and this is the code generated by jsoncpp to parse JSON from std::cin and extract its values (replace USE_VAL as needed):
value x(ctx);
std::cin >> x;
if (x.soap->error)
exit(EXIT_FAILURE); // error parsing JSON
#define USE_VAL(path, val) std::cout << path << " = " << val << std::endl
if (x.has("appDesc"))
{
if (x["appDesc"].has("description"))
USE_VAL("$.appDesc.description", x["appDesc"]["description"]);
if (x["appDesc"].has("message"))
USE_VAL("$.appDesc.message", x["appDesc"]["message"]);
}
if (x.has("appName"))
{
if (x["appName"].has("description"))
USE_VAL("$.appName.description", x["appName"]["description"]);
if (x["appName"].has("message"))
USE_VAL("$.appName.message", x["appName"]["message"]);
if (x["appName"].has("imp"))
{
for (int i2 = 0; i2 < x["appName"]["imp"].size(); i2++)
USE_VAL("$.appName.imp[]", x["appName"]["imp"][i2]);
}
}
This code uses the JSON C++ API of gSOAP 2.8.28. I don't expect people to change libraries, but I think this comparison helps to put JSON C++ libraries in perspective.
An example on how to use that would be great. There is a couple of examples at the Qt forum, but you're right that the official documentation should be expanded.
QJsonDocument on its own indeed doesn't produce anything, you will have to add the data to it. That's done through the QJsonObject, QJsonArray and QJsonValue classes. The top-level item needs to be either an array or an object (because 1 is not a valid json document, while {foo: 1} is.)