I am trying to parse json with Qt but I have no success. This is the ouput that I get from the server:
[{"anni":2019},{"anni":2018},{"anni":2017}]
Where that's generated from this simple php:
header('Content-Type: application/json');
echo json_encode($data);
The $data is an array containing the values you see above. I am using this piece of code in Qt 5.11.2:
void MainWindow::showYears() {
//reply is a QNetworkReply* reply;
if (reply->error() != QNetworkReply::NoError) {
//some error managment
} else {
auto responsedata = reply->readAll();
QJsonArray years = QJsonDocument::fromJson(responsedata).array();
qDebug() << QString{responsedata};
for(const QJsonValue& y : years) {
QJsonObject obj = y.toObject();
//doing "qDebug() << r" shows that r is "" (empty!)
auto r = obj["anni"].toString();
ui->comboBoxP->addItem(r);
}
}
}
What's wrong here?
Please note that qDebug() << QString{responsedata}; prints "[{\"anni\":2019},{\"anni\":2018},{\"anni\":2017}]"
The value for your field anni is an integer. Using the member function toString will not convert it to a string representation. it will return NULL. http://doc.qt.io/qt-5/qjsonvalue.html#toString
Try with: auto r = QString::number(obj["anni"].toInt());
Related
I am trying to read Json from a file, that I have previously created using QT, so it should be proper Json. Furthermore I have already implemented such a functionality in another program of mine, in which it worked fine and still works, so I basically copied the functions into the new program, but now I am recieving a weird error and cant fix it.
Error: "Exception thrown: read access violation.
e was 0xFFFFFFFFFFFFFFF7."
kegelbuch.cpp(void Kegelbuch::load(QString path):
void Kegelbuch::load(QString path, QString tab) {
//Load json file
Datastream* loadStream = new Datastream;
QJsonObject data = loadStream->loadData(path); //Error
if (data.contains("KeglerFullName") && data["KeglerFullName"].isArray()) {
QJsonArray keglerFullName = data["KeglerFullName"].toArray();
for (auto fullName : keglerFullName) {
if (fullName.isString()) {
QLineEdit* fullNameEdit = new QLineEdit;
fullNameEdit->setText(fullName.toString());
ui.keglerTab->layout()->addWidget(fullNameEdit);
}
}
}
else if (data.contains("KeglerShortName") && data["KeglerShortName"].isArray()) {
QJsonArray keglerShortName = data["KeglerShortName"].toArray();
for (auto shortName : keglerShortName)
{
if (shortName.isString()) {
QLineEdit* shortNameEdit = new QLineEdit;
shortNameEdit->setText(shortName.toString());
ui.keglerTab->layout()->addWidget(shortNameEdit);
}
}
}
}
datastream.cpp(const QJsonObject& Datastream::loadData(QString path)):
const QJsonObject& Datastream::loadData(QString path) {
QFile loadFile(saveFormat == Json
? QStringLiteral("data.json")
: QStringLiteral("data.dat"));
if (!loadFile.open(QIODevice::ReadOnly)) {
qWarning("Couldn't find/open the save file.");
QJsonObject returnObject;
return returnObject;
}
QByteArray saveData = loadFile.readAll();
QJsonDocument loadDoc(saveFormat == Json
? QJsonDocument::fromJson(saveData)
: QJsonDocument(QCborValue::fromCbor(saveData).toMap().toJsonObject()));
return loadDoc.object();
}
data.json
{
"KeglerFullName": [
"sadfg",
"ftzjtzc",
"restes",
"sxrtfgh"
],
"KeglerShortName": [
"waf",
"drxht",
"dsfgh",
"dft"
]
}
Thanks!
I have a json like this:
{
"name1": {
"path": "D:/myfolder"
},
"name2": {
"path": "D:/anotherFolder"
},
"name3": {
"path": "D:/myfolder"
}
}
And I want to get: are the names and the folder names.
like :
name1, D:/myfolder
name2, D:/anotherFolder
name3, D:/myfolder
It is not important if i get them independently or in an map, because i want to save them
to new variables into another struct.
what I have so far is:
QString jsonFile = "myjson.json";
QFile loadFile(jsonFile);
if(!loadFile.open(QIODevice::ReadOnly)){
qDebug() << "Failed to open " << loadFile; }
QByteArray data = loadFile.readAll();
QJsonDocument loadDoc(QJsonDocument::fromJson(data));
QJsonObject json = loadDoc.object();
QStringList keys = json.keys(); // <------- that give me the names. check.
But i didnt get it: how to get the second element?!?
the nearest approche so far was to get the "2nd dimension" with foreach:
foreach(const QJsonValue path, json ){
qInfo() << path;
}
this gave me as output:
QJsonValue(object, QJsonObject({"path": "D:/myfolder"}))
QJsonValue(object, QJsonObject({"path": "D:/anotherFolder"}))
QJsonValue(object, QJsonObject({"path": "D:/myfolder"}))
Most optimal way to do it just using single for iteration
QJsonDocument doc = QJsonDocument::fromJson(data);
QJsonObject json = doc.object();
for (auto it = json.constBegin(); it != json.constEnd(); ++it)
{
qInfo() << it.key() << it.value().toObject().value("path").toString();
}
You have to iterate through the keys obtaining the value, and then access the last one using the key "path":
QJsonDocument loadDoc = QJsonDocument::fromJson(data);
QJsonObject json = loadDoc.object();
for(const QString & key : json.keys()){
qInfo() << key << json[key].toObject()["path"].toString();
}
this is my first post here!
I'm working on a code that parses Json to fill a struct that I append to a Qlist of tests to run.
My problem is with the payload inside my struct: when I send the first object in my list the payload it is not empty when it should be.
struct FrameTest {
QString protocol;
QString Length;
QByteArray *payload;
};
QList<FrameTest> _validTestLists;
FrameTest TxFrame;
Code of the JSON parser
void Cesa::JsonParser(QJsonObject _ScriptTestObject)
{
TxFrame.protocol = "00";
TxFrame.Length = "00";
TxFrame.payload = new QByteArray();
for(QJsonObject::iterator it = _ScriptTestObject.begin(); it!=_ScriptTestObject.end(); ++it)
{
TxFrame.protocol= "00";
TxFrame.Length = "00";
TxFrame.payload->clear();
_CmdObject = _ScriptTestObject.value(key).toObject(); // Get Json object
if (_CmdObject.contains("Board") && _CmdObject.value("Board") == "Exia")
{
QString payload;
TxFrame.protocol= "03";
TxFrame.Length = "06";
payload = QString("%1").arg(obj.value("hopPeriod").toInt(), 2, 16, QChar('0'));
}
else if (_CmdObject.contains("Board") && _CmdObject.value("Board") == "Cevee")
{
TxFrame.protocol= "03";
TxFrame.Length = "06";
}
_testLists.append(TxFrame);
}
Test(_testLists); // Test with only one object
Function for sending via port COM
bool Cesa::Test(FrameTest frame)
{
QByteArray txFrame;
/* Transmit command */
txFrame.insert(0, frame.protocol);
txFrame.insert(2, frame.Length);
txFrame.insert(4, *frame.payload);
_comPort->write(QByteArray::fromHex(txFrame));
}
I'm a student still learning coding, any help and advice will be appreciated :)
I work with Qt and I try to send by http request a file like an image or a video to my NodeJS server.
I have a problem with the data send, when I read the file and I send to the server the data I don't receive the good character. I guess the problem come from the unicode, utf16 or something like that because it is working with a file.txt and not with an image.jpg
This is my function where I read and send the file. This one is called until the read function ended.
void FileManager::sendFileDataToServer(QString pathFile, QString location) {
CredentailsTable cdt;
if (_qfile->isOpen())
{
QString data;
if (!_in->atEnd()) {
data = _in->read(_socketManager->getBufferSize()); // read file
cdt.addCredential("name", getNameFile(_pathSendFile)); // set data
cdt.addCredential("msg", data);
_fileRequest->request(FileRequest::POST, FileRequest::Write, cdt);
}
else {
_qfileTest->close();
qDebug("End file");
}
}
else
qDebug("Error open file");
}
This function is called every time when the server respond
void FileManager::responseSendFileDataToServer(QNetworkReply *reply) {
if (reply->error() != 0)
{
qDebug("Il y a eu une erreur sur le server %d", reply->error());
return ;
}
else
this->sendFileDataToServer(_pathSendFile, _locationFileServer);
}
This is where my request is send
void ServiceRequest::request(Type type, int request, QByteArray cdt) {
QString strRequest = "REQUEST : http://" + _host + _prefixRoute + getRoute(request);
qDebug(strRequest.toStdString().c_str());
switch (type) {
case POST: {
QNetworkRequest networkRequest = QNetworkRequest(QUrl("http://" + _host + _prefixRoute + getRoute(request)));
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QNetworkReply *replyPost = this->post(networkRequest, cdt);
connect(replyPost, static_cast<void(QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error), this, &ServiceRequest::slotError);
connect(replyPost, &QNetworkReply::sslErrors, this, &ServiceRequest::slotSslErrors);
break;
}
My nodeJS function :
var write = function(req, res) {
fs.appendFile("users/" + req.body.name, req.body.msg, "UCS2",
function(err) {
return res.status(200).json(err);
})
}
How can I retrieve the integer value from the QJsonValue object? Suppose that I have the following JSON data:
{
"res": 1,
"message": "Common error"
}
I need to extract the "res" value from this data, so I've tried to use the following code:
QJsonDocument d = QJsonDocument::fromJson(some_json_data.toUtf8());
QJsonObject root_object = d.object();
QJsonValue res = root_object.value("res");
But I've found that QJsonValue class doesn't have a member function toInt or something like this (there's toDouble, toString, etc only). What can I do in such a situation? What is the best way to extract integer values via QjsonValue class?
(tl;dr: a one-liner solution at the end of answer.)
First a comprehensive way giving you full control. Below code assumes int is enough range for your integers, but could be expanded to work for most of the range of int64_t (but better test the boundary cases to get it fully correct):
QJsonValue res = root_object.value("res");
int result = 0;
double tmp = res.toDouble();
if (tmp >= std::numeric_limits<int>::min() && // value is not too small
tmp <= std::numeric_limits<int>::max() && // value is not too big
std::floor(tmp) == tmp // value does not have decimals, if it's not ok
) {
result = std::floor(tmp); // let's be specific about rounding, if decimals are ok
} else {
// error handling if you are not fine with 0 as default value
}
A shorter way using QVariant, and as an example also getting result into a larger integer type, if you just want to let Qt do it's thing. I'm not sure how it it handles integer values which are too big for a double to handle accurately, so again if that is important, better test.
QJsonValue res = root_object.value("res");
QVariant tmp = res.toVariant();
bool ok = false;
qlonglong result = tmp.toLongLong(&ok);
if (!ok) {
// error handling if you are not fine with 0 as default value
}
or same as error-ignoring one-liner, change integer type as appropriate:
qlonglong result = root_object.value("res").toVariant().toLongLong();
int QJsonValue::toInt(int defaultValue = 0) const
Converts the value to an int and returns it.
If type() is not Double or the value is not a whole number, the
defaultValue will be returned.
QByteArray JSettings::read_file(QString path)
{
QFile file;
file.setFileName(path);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return QByteArray();
QByteArray barray = file.readAll();
file.close();
return barray;
}
QVariantMap JSettings::to_map(QByteArray json)
{
QJsonDocument jdoc = QJsonDocument::fromJson(json);
QVariantMap vmap = jdoc.toVariant().toMap();
// qDebug() << vmap["res"].toInt();
return vmap;
}
QJsonObject JSettings::to_object(QByteArray json)
{
QJsonDocument jdoc = QJsonDocument::fromJson(json);
QJsonObject obj = jdoc.object();
// qDebug() << obj["res"].toInt();
return obj;
}
Qt JSON portal: http://doc.qt.io/qt-5/json.html
QJsonDocument d = QJsonDocument::fromJson(some_json_data.toUtf8());
QJsonObject root_object = d.object();
QJsonValue res = root_object.value("res");
int i = res.toString().toInt();
this is working, QString to Int