How to parse QJsonArray? - c++

In my QT application, there is a need to store the value of structures of the same type in a JSON dictionary.
I know about the [JSON Save Game Example article][1], 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:
I have a JSON document:
{
"devices": [
{
"name": "some name",
"price": 2000,
"year": 2022
}
]
}
I use the following code to read the information:
//open my JSON
QFile file("path/to/myfile.json");
file.open(QIODevice::ReadOnly);
QByteArray jsonData = file.readAll();
//finding array
QJsonDocument document = QJsonDocument::fromJson(jsonData);
QJsonObject object = document.object();
QJsonArray temp_array = object["devices"].toArray();
//reading
qDebug() << temp_array[0].toObject().value("name").toString(); //returned ""
qDebug() << temp_array.size(); //returned 0
qDebug() << temp_array.empty(); //returned true
qDebug() << object.keys(); //returned QList("devices")
As I previously pointed out in a comment, trying to read the values of the "name" key returned me an empty string, the size and empty functions indicate that I'm looking at an empty array. However, the keys function indicates that my json object still contains the "devices" key.
What could be the problem?
[1]: https://doc.qt.io/qt-5/qtcore-serialization-savegame-example.html

Your code seems to be doing correct things in correct order but something goes wrong. Either your file is not found or it doesn't get opened, or it is found but parsing fails.
You would find out if you did some checks instead of just assuming things work.
Below you will find example of robust programming. The example code checks
if file exists
if file opening fails
if file parsing to JSON fails
if file is actually JSON object (and not e.g. JSON array)
if size of the JSON array named "devices" is bigger than zero
if object in JSON array contains "name" property
if "name" property type is string
(I didn't try to compile the code, but I'm sure you get the idea and figure out what went wrong. If you made this kind of code to a function you would either return or throw exception when things go wrong...)
QFile file("path/to/myfile.json");
if (!file.exists()) {
qWarning() << "File doesn't exist";
}
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << "Couldn't open file";
}
QByteArray jsonData = file.readAll();
QJsonParseError parseError;
QJsonDocument document(QJsonDocument::fromJson(jsonData, &parseError));
if (parseError.error != QJsonParseError::NoError) {
qWarning() << "Invalid json file. Parsing failed:" << parseError.error << parseError.errorString();
}
if (!document.isObject()) {
qWarning() << "File is not JSON object!";
}
const QJsonObject &object = document.object();
QJsonArray temp_array = object["devices"].toArray();
if (temp_array.size() < 1) {
qWarning() << "JSON array object count:" << temp_array.size();
}
QJsonObject jsonObj = temp_array[0].toObject();
if (jsonObj.contains("name")) {
if (jsonObj["name"].isString()) {
qDebug() << jsonObj["name"].toString();
} else {
qWarning() << "name" << "is not string!";
}
} else {
qWarning() << "Object in JSON array did not have" << "name";
}

Related

How do you delete a sub-string in a string(qstring) in Qt

Is there a function in Qt similar to delete() and copy() in Delphi.
I am reading data from a device connected to my computer via USB and storing it as a QString. Every line that is read is not the same (or is cut short, even while using readyRead). I created a buffer sting to add these "half sting" (eg. string = "This" instead of "This is a string#") to and now I want to copy the string up until the '#' and then delete the string so if new "half stings" get added I can do the same with them. The code below is what I tried
void MainWindow::readSerial()
{
QByteArray serialData = port->readAll();
serialBuffer += serialData;
QByteArray serialString = serialBuffer.
qDebug() << serialString;
ui -> textEdit ->append(serialString);
//serialBuffer.replace(serialString,"");
}
The above code only returns an empty string.
void MainWindow::readSerial()
{
QByteArray serialData = port->readAll();
serialBuffer += serialData;
QString serialString = serialBuffer.mid(serialBuffer.indexOf("$"),serialBuffer.indexOf("\r\n"));
qDebug()<< "index of \r\n" << serialBuffer.indexOf("\r\n");
qDebug() << "SerialString" <<serialString;
ui -> textEdit ->append(serialString);
qDebug() << "SerialBuffer: " << serialBuffer;
serialBuffer.replace(serialString + "\r\n","");
}
the above code works. Thanks all.
regards

Converting JSON array to QByteArray

I have an array: [0xa,0x0b,0x0c]
This is stored in QJsonArray, I want to cover this to a QByteArray. I've been searching around for a solution and have come across several methods, this is what I have tried but its not right:
QJsonObject::iterator itrBinary = objJSON.find(clsFileThread::mscszBinary);
if ( itrBinary != objJSON.end() ) {
QJsonArray aryBinary(itrBinary->toArray());
//At this point aryBinary contains:
//10,11,12 which is correct
QJsonDocument doc(aryBinary);
QByteArray aryBytes(doc.toBinaryData());
//Now aryBytes contains:
//'q','b','j' why, how?
qDebug() << aryBinary << aryBytes;
}
After the qDebug I get:
QJsonArray([10,11,12]) "qbjs\x01\x00\x00\x00\x18\x00\x00\x00\x06\x00\x00\x00\f\x00\x00\x00J\x01\x00\x00j\x01\x00\x00\x8A\x01\x00\x00"
What I want in QBytesArray is exactly what was put into the QJsonArray, 10, 11, 12.
Thank you to "eyllanesc" for input, I would have thought there would be a built in function to do this, but here is the solution:
QJsonArray aryBinary(itrBinary->toArray());
QJsonArray::iterator itrArray = aryBinary.begin();
QByteArray aryBytes;
while( itrArray != aryBinary.end() ) {
aryBytes.append(static_cast<char>(itrArray->toInt()));
itrArray++;
}
qDebug() << aryBinary << aryBytes;

read JSON line by line with QT [duplicate]

This question already has answers here:
Foreach Through QJsonObject to get Key/Value Pair
(2 answers)
Closed 4 years ago.
I have a JSON like this:
{
"09:32 24.09.2018": "456",
"09:56 24.09.2018": "854",
"09:57 24.09.2018": "854",
"09:59 24.09.2018": "853",
"10:00 24.09.2018": "369",
"10:01 24.09.2018": "369"
}
How can I read this line by line in QT5. I would like to write it in a QTableWidget to have "09:32 24.09.2018" in first row / first column, "456" in first row / second column, "09:56 24.09.2018" second row / first column and so on..
My current loading works like this:
QJsonDocument getFile = loadJson("test");
QJsonObject obj = getFile.object();
with:
QJsonDocument MainWindow::loadJson(QString fileName) {
QFile jsonFile(fileName);
jsonFile.open(QFile::ReadOnly);
return QJsonDocument().fromJson(jsonFile.readAll());
}
Thank you.
you can iterate over the QJsonObject to transverse it:
QString val;
QFile file;
//set the file name
file.setFileName("foo.json");
//open the file name
file.open(QIODevice::ReadOnly | QIODevice::Text);
//read the file name
val = file.readAll();
//close the file name
file.close();
//string to json doc
QJsonDocument doc = QJsonDocument::fromJson(val.toUtf8());
//json doc to json object
QJsonObject object = doc.object();
//json object can be iterated
for (auto it = object.begin(), end=object.end(); it != end; ++it)
{
qDebug() << "Key: " << it.key() << "Val: " << it.value();
}

Blackberry 10 contact pic to byte array

I am working on migration application. I have to transfer blackberry 10 contacts to android.
I am getting problem in transferring contact pic. I am getting the uri of the pic, create file and try to read the bytes.
ContactPhoto contactPhoto = contact.primaryPhoto();
QString photo = contactPhoto.originalPhoto();
//photo = file:///accounts/1000/pimdata/_startup_data/contacts/2/img-tnqpx0.jpg
if (!photo.isEmpty()){
QFile file(photo);
if (file.open(QIODevice::ReadOnly)) {
qDebug() <<"file.readAll() IF" <<file.readAll() <<endl;
}else{
qDebug() <<"file.readAll() ELSE" <<endl;
}
vcardString += "PHOTO;JPEG;ENCODING=BASE64:" + (file.readAll() + "\n");
}
But else part of the below snip of code is executing
if (file.open(QIODevice::ReadOnly)) {
qDebug() <<"file.readAll() IF" <<file.readAll() <<endl;
}else{
qDebug() <<"file.readAll() ELSE" <<endl;
}
How I read bytes from below uri
file:///accounts/1000/pimdata/_startup_data/contacts/2/img-tnqpx0.jpg
As I suspected, removing file:// from the url works.
Here's the code I used to test :
bb::pim::contacts::ContactPhoto contactPhoto = contact.primaryPhoto();
QString photo = contactPhoto.originalPhoto();
if (!photo.isEmpty()){
QFile file(photo.remove("file://"));
if (file.open(QIODevice::ReadOnly)) {
qDebug() <<"file.readAll() IF" <<file.readAll() <<endl;
}else{
qDebug() <<"file.readAll() ELSE" <<endl;
}
}
Please note that you need to leave one / in front of the url, so your picture url shared in OP would look like :
/accounts/1000/pimdata/_startup_data/contacts/2/img-tnqpx0.jpg
Also, if your goal is to create a VCard vcf file, you don't need to manually create the VCard file content, don't even need to read the bytes of the photo file, the contactToVCard function will do that for you.
QByteArray vcard = contactService.contactToVCard(contact.id(), bb::pim::contacts::VCardPhotoEncoding::BASE64, -1);
qDebug() << "vcard:" << vcard;

QXmlStreamReader not parsing xml file

I'm having trouble reading the follwing Xml file:
<ArrayOfScore xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Score><GameKey>201610629</GameKey><SeasonType>1</SeasonType><Season>2016</Season><Week>6</Week><Date>2016-10-13T20:25:00</Date><AwayTeam>DEN</AwayTeam><HomeTeam>SD</HomeTeam><AwayScore>13</AwayScore><HomeScore>21</HomeScore><Channel i:nil="true"/><PointSpread>3.0</PointSpread><OverUnder>44.5</OverUnder><Quarter>F</Quarter><TimeRemaining i:nil="true"/><Possession i:nil="true"/><Down i:nil="true"/><Distance i:nil="true"/><YardLine i:nil="true"/><YardLineTerritory i:nil="true"/><RedZone i:nil="true"/><AwayScoreQuarter1>0</AwayScoreQuarter1><AwayScoreQuarter2>3</AwayScoreQuarter2><AwayScoreQuarter3>0</AwayScoreQuarter3><AwayScoreQuarter4>10</AwayScoreQuarter4><AwayScoreOvertime>0</AwayScoreOvertime><HomeScoreQuarter1>7</HomeScoreQuarter1><HomeScoreQuarter2>3</HomeScoreQuarter2><HomeScoreQuarter3>9</HomeScoreQuarter3><HomeScoreQuarter4>2</HomeScoreQuarter4><HomeScoreOvertime>0</HomeScoreOvertime><HasStarted>true</HasStarted><IsInProgress>false</IsInProgress><IsOver>true</IsOver><Has1stQuarterStarted>true</Has1stQuarterStarted><Has2ndQuarterStarted>true</Has2ndQuarterStarted><Has3rdQuarterStarted>true</Has3rdQuarterStarted><Has4thQuarterStarted>true</Has4thQuarterStarted><IsOvertime>false</IsOvertime><DownAndDistance i:nil="true"/><QuarterDescription>Final</QuarterDescription><StadiumID>14</StadiumID><LastUpdated>2016-10-17T14:27:48</LastUpdated><GeoLat>32.783188</GeoLat><GeoLong>-117.119439</GeoLong><ForecastTempLow>58</ForecastTempLow><ForecastTempHigh>76</ForecastTempHigh><ForecastDescription>Sunny</ForecastDescription><ForecastWindChill>70</ForecastWindChill><ForecastWindSpeed>14</ForecastWindSpeed><AwayTeamMoneyLine>-160</AwayTeamMoneyLine><HomeTeamMoneyLine>140</HomeTeamMoneyLine><Canceled>false</Canceled><Closed>true</Closed><LastPlay i:nil="true"/><StadiumDetails><StadiumID>14</StadiumID><Name>Qualcomm Stadium</Name><City>San Diego</City><State>CA</State><Country>USA</Country><Capacity>70561</Capacity><PlayingSurface>Grass</PlayingSurface><GeoLat>32.783188</GeoLat><GeoLong>-117.119439</GeoLong></StadiumDetails></Score></ArrayOfScore>
I use the following code to try to read the elements:
QFile testxml("./test.xml");
if(testxml.open(QIODevice::ReadOnly)) {
QXmlStreamReader XMLData(&testxml);
while(!XMLData.atEnd() && !XMLData.hasError()) {
XMLData.readNext();
qDebug() << XMLData.readElementText();
if(XMLData.isStartElement()) {
qDebug() << XMLData.name();
qDebug() << XMLData.readElementText();
}
}
}
But I only get two empty strings.
I have tried reading another Xml file which looks very similar and which is also everything in one line and I can successfully parse the elements. With this file it is somehow not working.
Does anyone have any idea what could I be doing wrong?