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.
Related
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);
I am using some functions to convert QVector's to QByteArray's, for example:
QByteArray Serialize::serialize(QVector<double> data)
{
QByteArray byteArray;
QDataStream out(&byteArray, QIODevice::WriteOnly);
out << data;
return byteArray;
}
void Serialize::deserialize(QByteArray byteArray, QVector<double> *data)
{
QDataStream in(&byteArray, QIODevice::ReadOnly);
in >> *data;
}
Now, that I have the QByteArray I need to put it in a text file, how can I convert it to QString?
I already tried the simplest way:
QString myString(data); // data - QByteArray
But myString is always empty.
I also found the toStdString() function in the documentation, but it was introduced only in Qt 5.4.
I'm using Qt 5.3.
Follows a complete example:
#include <QCoreApplication>
#include <QDebug>
#include <QVector>
#include <QByteArray>
#include <QDataStream>
QByteArray serialize(QVector<double> data)
{
QByteArray byteArray;
QDataStream out(&byteArray, QIODevice::WriteOnly);
out << data;
return byteArray;
}
void deserialize(QByteArray byteArray, QVector<double> *data)
{
QDataStream in(&byteArray, QIODevice::ReadOnly);
in >> *data;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QVector<double> data;
data << 1.1 << 2.2 << 3.3 << 4.4 << 5.5 << 6.6 << 7.7 << 8.8 << 9.9;
QByteArray byteArray = serialize(data);
QVector<double> dataConverted;
deserialize(byteArray, &dataConverted);
qDebug() << "Data:";
qDebug() << data;
qDebug() << "ByteArray:";
QString test(byteArray);
qDebug() << test;
qDebug() << "Data Converted:";
qDebug() << dataConverted;
return a.exec();
}
Note: The general objective of this is to generate a SQL file with all content from the SQLite database. My double vector is converted to QByteArray and stored as BLOB into the database (using the serialize function). When I need to load it from the database I use the deserialize function to convert to a double vector again. Now I need to generate the SQL file with the data in the BLOB format, then I can directly import it into another database.
The problem is that a byte array is type-agnostic data type, it simply represents a collection of individual bytes in memory. In your example code you are creating the byte array from a vector of doubles, and then converting back to another vector of doubles. No problem.
However when you pass the byte array into the QString constructor, the QString is trying to interpret the byte array as data that represents a string, for example an array of ASCII character codes.
Some string classes might let you do this, and create an instance filled with garbage, however QString appears to be doing some basic error checking and helping you out by giving you an empty string.
As for some code to print out the contents of a byte array of doubles, the deserialize method you've provided is not too bad an example.
Use QTextCodec to convert from QByteArray to QString, here's an example from official docs:
QByteArray encodedString = "...";
QTextCodec *codec = QTextCodec::codecForName("KOI8-R");
QString string = codec->toUnicode(encodedString);
And to make the example work, you need to convert the doubles to QStrings during serialization:
QByteArray serialize(QVector<double> data)
{
QByteArray byteArray;
QDataStream out(&byteArray, QIODevice::WriteOnly);
for (double d : data) {
out << QString::number(d);
}
return byteArray;
}
If you don't want to convert individual numbers to string, you can also "stringify" the QByteArray with byteArray.toHex():
qDebug() << "ByteArray:";
QString test(byteArray.toHex());
I'm new in Qt and can't find any solution in Qt libraries.
I'd like to find smth without loop usage.
Is there any way to convert QByteArray to QString with - between bytes?
For example:
QByteArray = XX1F2C5A
QString = "XX-1F-2C-5A".
Yeah you can with QString::replace:
QByteArray b = "XX1F2C5A";
QString s(b);
qDebug() << s;
s.replace(QRegExp("(..)[^$]"), QString("\\1-"));
qDebug() << s;
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"];
}
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"