Qt parse a json response - c++

I need to parse a json response that looks like this and to get the id value, i.e. blabla2:
{
"kind": "blabla",
"id": "blabla2",
"longUrl": "blabla3"
}
How do I do that? I tried to use Qjson, but when I try to buid it to get the .dll, I get an error:
xlocale.h is missing.
Are there other alternatives? Thanks.

Looking at the documentation for QJsonDocument you can read the file into a QByteArray and then do the following: -
// assuming a QByteArray contains the json file data
QJsonParseError err;
QJsonDocument doc = QJsonDocument::fromJson(byteArray, &err);
// test for error...
Then use the function on the QJsonDocument to retrieve the top level object...
if(doc.isObject())
{
QJsonObject obj = doc.object();
QJsonObject::iterator itr = obj.find("id");
if(itr == obj.end())
{
// object not found.
}
// do something with the found object...
}
There is also a value() function in QJsonObject, so instead of using the iterator and calling find, you may simply be able to call: -
QJsonValue val = obj.value("id");
Disclaimer: I present this code after having just read the Qt documentation, so do not just copy and paste this, but consider it more as pseudo code. You may need to edit it a little, but hope that helps.

I would encourage you to use Qt 5 or backport the json classes to Qt 4. Your software will be more future proof then when you intend to port it to Qt 5 since you will need to rewrite the json parsing then available in QtCore.
I would write something like the code below, but please double check it before using it in production as I may have missed an error checking while writing it. Regardless of error checking, the output is what you wanted to get.
main.cpp
#include <QFile>
#include <QByteArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QDebug>
int main()
{
QFile file("main.json");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "Could not open the file" << file.fileName() << "for reading:" << file.errorString();
return 1;
}
QByteArray jsonData = file.readAll();
if (file.error() != QFile::NoError) {
qDebug() << QString("Failed to read from file %1, error: %2").arg(file.fileName()).arg(file.errorString());
return 2;
}
if (jsonData.isEmpty()) {
qDebug() << "No data was currently available for reading from file" << file.fileName();
return 3;
}
QJsonDocument document = QJsonDocument::fromJson(jsonData);
if (!document.isObject()) {
qDebug() << "Document is not an object";
return 4;
}
QJsonObject object = document.object();
QJsonValue jsonValue = object.value("id");
if (jsonValue.isUndefined()) {
qDebug() << "Key id does not exist";
return 5;
}
if (!jsonValue.isString()) {
qDebug() << "Value not string";
return 6;
}
qDebug() << jsonValue.toString();
return 0;
}
main.pro
TEMPLATE = app
TARGET = main
QT = core
SOURCES += main.cpp
Build and Run
qmake && make && ./main
Output
"blabla2"

Related

Minimal Example on how to read, write and print QJson code (with QJsonDocument, QJsonArray, QJsonObject, QFile)

I am searching for a minimal full executable qt or c++ code example to parse and write this Json code:
{
"FirstName": "John",
"LastName": "Doe",
"MiddleName": null,
"Age": 43,
"Address": {
"Street": "Downing Street 10",
"City": "London",
"Country": "Great Britain"
},
"Phone numbers": [
"+44 1234567",
"+44 2345678"
]
"Valid":true,
}
The above example consists of an object with 5 key/value pairs. Two of the values are strings, one is a number,
one is another object and the last one an array.
A valid JSON document is either an array or an object, so a document always starts with a square or curly bracket.
EDIT:
Json has 2 more key/value pairs - value 'null' and 'bool'
And yes, I have seen a "Save Game Example"
and tried to figure it out.
But after nearly a week I gave up to transfer a minimal Example without enums, QVectors and 3 different header Files over to my project to handle the code snippet. Doesn't matter if its for a widget or core code.
I already did a xml read and write program successfully but it seems I miss some Important point and get errors with json that may or may not have to do with the parsing. I am not able to rule it out without a minimal fully working code example.
So my question is: Could you please provide a minimal Example to write, read and print the Json file? Thanks upfront.
Since there does not seem to be a clear example on SO I wrote one.
It uses simple mutation to create the objects, but if you have access to C++11 you should take a look at the std::initializer_list constructors, they make construction of objects much more compact.
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <QtGlobal>
#include <QTextStream>
#include <QDebug>
int main() {
// 1. Create the document
QJsonObject root;
root["FirstName"] = "John";
root["LastName"] = "Doe";
root["Age"] = 43;
// Construct nested object first, then store it in `root`
QJsonObject Address;
Address["Street"] = "Downing Street 10";
Address["City"] = "London";
Address["Country"] = "Great Britain";
root["Address"] = Address;
QJsonArray PhoneNumbers;
PhoneNumbers.push_back("+44 1234567");
PhoneNumbers.push_back("+44 2345678");
root["Phone Numbers"] = PhoneNumbers;
// `ba` contains JSON
QByteArray ba = QJsonDocument(root).toJson();
QTextStream ts(stdout);
ts << "rendered JSON" << endl;
ts << ba;
{
QFile fout("test.json");
fout.open(QIODevice::WriteOnly);
fout.write(ba);
}
// 2. Now read it back in
QJsonParseError parseError;
QJsonDocument doc2;
{
QFile fin("test.json");
fin.open(QIODevice::ReadOnly);
QByteArray ba2 = fin.readAll();
doc2 = QJsonDocument::fromJson(ba2, &parseError);
}
if (parseError.error != QJsonParseError::NoError) {
qWarning() << "Parse error at" << parseError.offset << ":" << parseError.errorString();
} else {
ts << "parsed JSON" << endl;
ts << doc2.toJson(QJsonDocument::Compact);
//or QJsonDocument::Indented for a JsonFormat
}
}
I guess it might help someone else too, I figured it all out,
thanks to #Botje for his example, really helped.
In general it is easy for me to remember to represent data as QByteArray
in the memory.
A minimal example to access and also use every single value stored in a json file, you are welcome:
(Yes, I could have written it even more compact but I guess this makes it easier to understand, so I spared functions/classes/structs for the sake of readability.)
#include <QCoreApplication>
#include <QString>
#include <QVariant>
#include <QFile>
#include <QByteArray>
#include <QTextStream>
#include <QDebug>
//json specific
#include <QJsonParseError>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonParseError>
#include <QJsonValue>
void writeJsonFile();
void readJsonFile();
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
writeJsonFile();
readJsonFile();
return a.exec();
}
void writeJsonFile()
{
qDebug() << "Write Json File: ";
//1. Create a QJsonObject and add values to it
QJsonObject jsonObj;
jsonObj["FirstName"] = "John";
//no value will be written as null in the json file
jsonObj["MiddleName"];
jsonObj["LastName"] = "Doe";
jsonObj["Age"] = 43;
//2. Create Item of Json Object content (object of object)
QJsonObject jsonItemObj;
jsonItemObj["Street"] = "Downing Street 10";
jsonItemObj["City"] = "London";
jsonItemObj["Country"] = "Great Britain";
//3. Add jsonItemObj to jsonObj and give it an object Name
jsonObj["Address"] = jsonItemObj;
//4. Create jsonArray and fill it with values - similar to filling a vector
QJsonArray jsonArray;
jsonArray.append("+44 1234567");
jsonArray.append("+44 2345678");
//Add a bool to the Object
jsonObj["Valid"] = true;
//5. Add jsonArray to jsonObj and give it an object Name
jsonObj["Phone numbers"] = jsonArray;
//(It can also be added to the jsonItemObj to be inline with the Address section)
//with jsonItemObj["Phone numbers"] = jsonArray or as much objects of objects
//you need
/* As I understood it, most Qt classes use a QByteArray to handle data internally
* because it is really fast/efficient,
* also QFile QIODevice, it is a good idea to hold the read/write
* QIODevice data as QByteArray in the Memory
*/
//6. Create a QByteArray and fill it with QJsonDocument (json formatted)
QByteArray byteArray;
byteArray = QJsonDocument(jsonObj).toJson();
//7. Open a QFile and write the byteArray filled with json formatted data
//thanks to the QJsonDocument() Class to the file
QFile file;
file.setFileName("file.json");
if(!file.open(QIODevice::WriteOnly)){
qDebug() << "No write access for json file";
return;
}
//8. finally write the file and close it
file.write(byteArray);
file.close();
//9. Print out the byteArray to the terminal
QTextStream textStream(stdout);
textStream << "Rendered json byteArray text: " << endl;
textStream << byteArray << endl;
}
void readJsonFile()
{
qDebug() << "Read Json File:";
//1. Open the QFile and write it to a byteArray and close the file
QFile file;
file.setFileName("file.json");
if(!file.open(QIODevice::ReadOnly)){
qDebug() << "Json filef couldn't be opened/found";
return;
}
QByteArray byteArray;
byteArray = file.readAll();
file.close();
//2. Format the content of the byteArray as QJsonDocument
//and check on parse Errors
QJsonParseError parseError;
QJsonDocument jsonDoc;
jsonDoc = QJsonDocument::fromJson(byteArray, &parseError);
if(parseError.error != QJsonParseError::NoError){
qWarning() << "Parse error at " << parseError.offset << ":" << parseError.errorString();
return;
}
//3. Create a jsonObject and fill it with the byteArray content, formatted
//and holding by the jsonDocument Class
QJsonObject jsonObj;
jsonObj = jsonDoc.object();
//4. Now picking the jsonValues and printing them out or do what ever you need
QJsonValue jsonVal;
QTextStream textStream(stdout);
jsonVal = jsonObj.value("FirstName");
textStream << jsonVal.toString() << endl;
jsonVal = jsonObj.value("MiddleName");
//null gets back to an empty fild - added the sting "null/empty" to make it visible
textStream << jsonVal.toVariant().toString() << "null/empty" << endl;
jsonVal = jsonObj.value("LastName");
textStream << jsonVal.toString() << endl;
//The number has to be converted to an int and than to a string to print it
jsonVal = jsonObj.value("Age");
textStream << QString::number(jsonVal.toInt()) << endl;
//5. Now we need to fill the object of the object. To do that, we need
//the Item Object and a jsonSubVal object for json without a loop
QJsonObject jsonItemObj;
QJsonValue jsonSubVal;
jsonVal = jsonObj.value(QString("Address"));
jsonItemObj = jsonVal.toObject();
jsonSubVal = jsonItemObj["Street"];
textStream << jsonSubVal.toString() << endl;
jsonSubVal = jsonItemObj["City"];
textStream << jsonSubVal.toString() << endl;
jsonSubVal = jsonItemObj["Country"];
textStream << jsonSubVal.toString() << endl;
//6. now the Phone Numbers array with a loop
QJsonArray jsonArray;
jsonArray = jsonObj["Phone numbers"].toArray();
for(int i = 0; i < jsonArray.size(); i++)
textStream << jsonArray[i].toString() << endl;
textStream << "or with foreach" << endl;
foreach(QJsonValue v, jsonArray)
textStream << v.toString() << endl;
//7. And finally the bool value:
jsonVal = jsonObj.value(QString("Valid"));
textStream << jsonVal.toVariant().toString() << endl;
textStream << "or as number, not a string: ";
textStream << (QString::number(jsonVal.toInt())) << endl;
textStream << "\nThe whole file as printed in the file \n" <<
jsonDoc.toJson(QJsonDocument::Indented);

Parsing JSON starting with bracket `[` with Qt5

According to this, A JSON starting with bracket is valid, so i have encoded a list of item, in a test.json file:
[{"name": "a"},{"name": "b"}]
Heavily inspirated by this answer, i push this code in main.cpp:
#include <QApplication>
#include <QFile>
#include <QByteArray>
#include <QJsonObject>
#include <QJsonDocument>
#include <QVariant>
#include <QDebug>
#include <iostream>
int main(int argc, char *argv[]) {
// Reading the JSON, parse it, get data as QJsonObject
QString val;
QFile file;
file.setFileName("test.json");
file.open(QIODevice::ReadOnly | QIODevice::Text);
val = file.readAll();
file.close();
QJsonDocument d = QJsonDocument::fromJson(val.toUtf8());
QJsonObject sett2 = d.object();
// Printings
qWarning() << "File content: " << val;
qWarning() << "sett2: " << sett2 << " (empty: " << sett2.empty() << ')';
// try to access the data directly
QJsonValue value = sett2.value(QString("name"));
qWarning() << "name value: " << value;
QJsonObject item = value.toObject();
qWarning() << "QJsonObject of accessed value: " << item;
}
Here is the output:
File content: "[{\"name\": \"a\"},{\"name\": \"b\"}]\n"
sett2: QJsonObject() (empty: true )
name value: QJsonValue(undefined)
QJsonObject of accessed value: QJsonObject()
We see that the file is properly readed. However, no data seems to be accessed : sett2 is empty, as if holding no data.
After searching on the QJsonObject documentation, i can't found any routine that can give access to the data in the file, in this case: the only one that seems to allow an access to fields is the value(), method, but it needs a parameter.
Call it with 0, 1, NULL "name", "a", "b" and "knock knock" lead to compilation error or empty data.
Other methods, like keys(), returns also empty data.
How access data of objects ? (here, name: "a" and name: "b")
The answere is simple - you have to call QJsonDocument::array() instead of object:
QJsonArray sett2 = d.array();

Qt - Writing integer data into JSON

I am using Qt (5.5) and I want to exchange data in JSON format in a client-server application.
So the format is constant:
{
"ball":
{
"posx": 12,
"posy": 35
}
}
I would like to be able to define a ByteArray or string like so:
QByteArray data = "{\"ball\":{\"posx\":%s,\"posy\":%s}}"
and then just write whatever the values for that into the string.
How do I do that?
QtJson is baked into Qt 5. It is easy to use, and gets it all ready for you pretty easily.
#include <QCoreApplication>
#include <QDebug>
#include <QJsonObject>
#include <QJsonDocument>
void saveToJson(QJsonObject & json);
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QJsonObject jsonObject;
saveToJson(jsonObject);
QJsonDocument jsonDoc(jsonObject);
qDebug() << "Example of QJsonDocument::toJson() >>>";
qDebug() << jsonDoc.toJson();
qDebug() << "<<<";
return a.exec();
}
void saveToJson(QJsonObject & json)
{
QJsonObject ball;
ball["posx"] = 12;
ball["posy"] = 35;
json["ball"] = ball;
}
output
Example of QJsonDocument::toJson() >>>
"{
"ball": {
"posx": 12,
"posy": 35
}
}
"
<<<
Note: qDebug() wraps QString objects in quotes when printing. To get rid of that, pass your QString into qPrintable(). And it puts endl in for you at the end of each line.
For a more complex example see the official:
JSON Save Game Example
http://doc.qt.io/qt-5/qtcore-json-savegame-example.html
Hope that helps.
And here are more examples of string manipulations, but for readability and maintainability, please use the QJson classes.
QString str;
str = QString("{\"ball\":{\"posx\":%1,\"posy\":%2}}").arg(12).arg(35);
qDebug() << qPrintable(str);
QByteArray ba = str.toLocal8Bit();
qDebug() << ba;
QString str2;
str2 = "{\"ball\":{\"posx\":"
+ QString::number(12)
+ ",\"posy\":"
+ QString::number(35)
+ "}}";
qDebug() << qPrintable(str2);
output
{"ball":{"posx":12,"posy":35}}
"{"ball":{"posx":12,"posy":35}}"
{"ball":{"posx":12,"posy":35}}
Note again that the quotes are added by qDebug() when printing a QByteArray object.
Hope that helps.

QUrl parsing in QT 5

I have a QUrl as this:
https://www.example.com/index.html#token=SomeToken&user=guest
and I want to obtain the value of the token i.e. SomeToken. I know about method QUrl::queryItemValue,so this code must work:
void MainWindow::get_token(QUrl url)
{
url = url.toString().replace("?","#");
QString token = url.queryItemValue("token");
}
but in Qt5 i can't use this method,how can I parse url?
There is new QUrlQuery class in Qt5. New QUrl doesn't support this method yet, so you should use QUrlQuery for parsing (it has this and other methods). Use
QUrlQuery query(url);
qDebug() << query.queryItemValue("token");
Note: be carefull with replace because QUrlQuery gives you correct result with
?token=SomeToken not a #token=SomeToken
http://qt-project.org/doc/qt-5/qurlquery.html
QUrlQuery queryItemValue method does not work properly in Qt 5.9 So i wrote my own function to parse GET parameters
#include <QCoreApplication>
#include <QUrlQuery>
#include <QDebug>
#include <QMap>
#include <QUrl>
QMap<QString,QString> ParseUrlParameters(QString &url)
{
QMap<QString,QString> ret;
if(url.indexOf('?')==-1)
{
return ret;
}
QString tmp = url.right(url.length()-url.indexOf('?')-1);
QStringList paramlist = tmp.split('&');
for(int i=0;i<paramlist.count();i++)
{
QStringList paramarg = paramlist.at(i).split('=');
ret.insert(paramarg.at(0),paramarg.at(1));
}
return ret;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QString url = "http://test1.ru/?token=test&email=test1";
QUrlQuery query(url);
qDebug() << "queryItemValue does not work in Qt 5.9.0 with dynamic QString" << query.queryItemValue("token") << "("<< endl;
qDebug() << "ParseUrlParameters(...) works fine..."<< endl;
QMapIterator<QString, QString> i(ParseUrlParameters(url));
while (i.hasNext())
{
i.next();
qDebug() << i.key() << ":" << i.value();
}
return a.exec();
}
I know this post is old but if my answer can help someone, I share :)
Tested under QT 5.15.2 and under QT 6.4.2
#include<QUrl>
#include<QUrlQuery>
#include<QDebug>
int main (int nbArg, char* listArg[])
{
// Initialization
QString myString = "https://www.factice.fr/demo.php?thing=123&subject=456&artificial=789";
QUrl myUrl(myString);
QUrlQuery myQuery(myUrl);
QMap<QString,QString> paramList; // Associative Array to Store Keys and Values
// For Each QPair
for(int i=0;i<myQuery.queryItems().size();i++)
{
// Information Display
qDebug() << myQuery.queryItems().at(i).first << " : " << myQuery.queryItems().at(i).second;
// Or Storage of Information for futur use
paramList.insert(myQuery.queryItems().at(i).first,myQuery.queryItems().at(i).second);
}
// End - For Each QPair
// Examples of Displaying Stored Information
qDebug() << paramList;
qDebug() << paramList["thing"];
}

Qt Qvariantlist conversion into javascript array unsuccessful

I'm currently create an apps in Meego using QML and JS on most of the part. and now I stumbled upon a problem.
From javascript I want to call a C++ function to read text file, parse it, and then return an array of the parsing result.
so I create a Q_INVOKABLE function called parse() and call it through javascript
function parse() {
var myArray = new Array();
myArray = parser.parse("/home/user/MyDocs/angklungtext.txt")
if(myArray === undefined){
console.log("null found");
}
for(var i = 0; i < myArray.length; i++){
console.log(myArray[i][0] + "," + myArray[i][1])
}
}
and here is the parse function in C++
QVariantList* QMLParser::parse(QString filename)
{
qDebug() << "start debugging";
qDebug() << filename;
qDebug() << QDir::currentPath();
QDir dir;
qDebug()<< dir.absoluteFilePath(filename);
QFile file(filename);
if(!file.exists())
{
qDebug() << "File: " << file.fileName() << "tidak ditemukan";
return NULL;
}
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
qDebug() << "Tidak dapat membuka file" << file.fileName() << "untuk ditulis";
return NULL;
}
QTextStream stream(&file);
QVariantList* myList = new QList<QVariant>;
while(!stream.atEnd())
{
QString line = stream.readLine();
qDebug() << line.trimmed();
QStringList lineList = line.split(":");
myList->append(lineList);
}
file.close();
return myList;
}
sadly.
when I try to run it it giving a result like this
start debugging
"/home/user/MyDocs/angklungtext.txt"
"/home/developer"
"/home/user/MyDocs/angklungtext.txt"
"1:1000"
"4:2000"
"5:3000"
"2:4000"
null found
file:///opt/memoryreader/qml/memoryreader/myjs.js:8: TypeError: Result of expression 'myArray' [undefined] is not an object.
looks like the C++ parse function successfully parsing the file. it can read it and it can save it into the QVariantList.
but after it return the result into javascript myArray still [undefined].
is there something wrong with the conversion?
Just simplify the C++ side like this :
QVariant QMLParser::parse(QString filename)
{
QStringList myList;
qDebug() << "start debugging";
qDebug() << filename;
qDebug() << QDir::currentPath();
QDir dir;
qDebug() << dir.absoluteFilePath(filename);
QFile file(filename);
if(!file.exists()) {
qDebug() << "File: " << file.fileName() << "tidak ditemukan";
return NULL;
}
if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "Tidak dapat membuka file" << file.fileName() << "untuk ditulis";
return NULL;
}
QTextStream stream(&file);
while(!stream.atEnd()) {
QString line = stream.readLine();
qDebug() << line.trimmed();
myList << line.trimmed().split(":");
}
file.close();
return QVariant::fromValue(myList);
}
And it should work !
Just remember, QML must see a QVariant, even if a QList is wrapped inside it, and Qt is able to convert most of its base types to QVariant using QVariant::fromValue(T) so use it extensively.
Oh and BTW a QVariant is reference not pointer.
Haven't done this myself, so I'm just thinking out loud. But I note that you're returning a pointer to a QVariantList...which looks suspect. (Also: if you new, then who would do the delete?)
Have you tried returning it by value?