Qt parsing json using network response binary - c++

Alright, I found something I just don't understand. I am making a request to a web service using QtNetworkManager. For some reason I can't seem to go from the network response to a jsondoc directly, I have to cast it into a string and then BACK into uft8?
void WebAPIengine::handleNetworkData(QNetworkReply *networkReply)
{
//No network error
if (!networkReply->error()){
//Cast to string
QString strReply = (QString)networkReply->readAll();
//This works, jsonDoc will have the json response from webpage
QJsonDocument jsonDoc = QJsonDocument::fromJson(strReply.toUtf8());
//This doesn't work, networkReply->readAll() is said to return a QByteArray.
QJsonDocument jsonDoc2 = QJsonDocument::fromBinaryData(networkReply->readAll());
QJsonObject jsonObj = jsonDoc.object();
data = jsonObj;
}
//Network error
else{
data["Error"] = "WebAPIengine::handleNetworkData()";
}
Now I can not understand why jsonDoc is working and jsonDoc2 is not. Can someone explain?

Once you do a QNetworkReply->readAll(), the QNetworkReply object will be empty. So if you call the QNetworkReply->readAll() method again, you will not get anything.
Moreover I don't understand why you are converting the QByteArray returned by QNetworkReply->readAll() into a QString and then converting it back to QByteArray(by calling QString::toUtf8()) to give it to the QJsonDocument::fromJson function.
You can try doing this:
QByteArray temp = newReply->readAll();
QJsonDocument jsonDoc = QJsonDocument::fromJson(temp); // This should work
Also make sure to know what the content of the JSon document is, i.e. if it is a map (QJsonObject), array(QJSonArray), array of maps or map with an array as value.

Related

How to load QJsonDocument from a file

Im trying to learn how to use JSON and Qt i have menaged and im having problem getting QJsonDocument from a file.The file opens correctly i can also see file's content with qDebug() but the QJsonDocument created from this file is always empty
if(stdButton==QDialogButtonBox::Ok)
{
qDebug()<<"accept button clicked";
QFile userList;
userList.setFileName("users.json");
userList.open(QIODevice::ReadOnly);
//using this qDebug i'm able to see files content
qDebug()<<QJsonDocument::fromJson(userList.readAll());
//but this QJsonDocument is always empty
QJsonDocument userDoc;
userDoc=QJsonDocument::fromJson(userList.readAll());
if(userDoc.isEmpty())
{
qDebug()<<"userDoc is empty";
}
qDebug()<<userDoc;
accept();
}
//but this QJsonDocument is always empty
QJsonDocument userDoc;
userDoc=QJsonDocument::fromJson(userList.readAll());
That's because there is nothing to read from the file since you have read everything from it in the previous call to readAll().
You can store the data from userList.readAll() and use it repeatedly.
QFile userList;
userList.setFileName("users.json");
userList.open(QIODevice::ReadOnly);
QByteArray data = userList.readAll();
qDebug()<<QJsonDocument::fromJson(data);
QJsonDocument userDoc;
userDoc=QJsonDocument::fromJson(data);

How to load base64 image data from json in QT

I am beginning with QT5 and trying to load an image from base64 json data. I can load directly from a base64 string but is unsuccessful when trying to load from json object.
the error i am getting is
error: conversion from 'QJsonValueRef' to non-scalar type 'QByteArray' requested
I tried changing toUtf8 toAcsii() etc. but similar error are being produced. Any help and suggestions will be much appreciated.
QString strReply = (QString)reply->readAll(); // json data from a servlet (created using gson library)
QJsonDocument jsonResponse = QJsonDocument::fromJson(strReply.toUtf8());
QJsonObject jsonObj = jsonResponse.object();
QByteArray imgbase64 = jsonObj["photo"]; // image data
QImage img;
img.loadFromData(QByteArray::fromBase64(imgbase64));
ui->outputImage->setPixmap(QPixmap::fromImage(img));
ui->outputImage->setScaledContents( true );
ui->outputImage->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored );
error: conversion from 'QJsonValueRef' to non-scalar type 'QByteArray' requested*
Since you didn't specify this, I'm expect that the error you're seeing is coming from this line: -
QByteArray imgbase64 = jsonObj["photo"]; // image data
Calling the [] operator on a QJsonObject returns a QJsonValue. There is no overloaded = operator in QByteArray to initialise it from a QJsonValue.
What you need to do is use the QJsonValue functions and do something like this: -
QByteArray imgbase64;
if(jsonObj["photo"].isString())
{
imgbase64 = jsonObj["photo"].toString().toUtf8();
}
Since the photo object is expected to be in Base64, it is acceptable as a string object.
Following code converts JSON object image field to QString and QString to QImage -
QString base64img = jsonObj["photo"].toString();
QByteArray by = QByteArray::fromBase64(base64img.toLatin1());
QImage img = QImage::fromData(by,"JPEG");

Why can't I parse the Cryptsy JSON API with Qt5/C++?

I'm trying to parse this JSON Web-API using Qt5 and C++ using QJsonDocument and QJsonObject as seen here. But I fail to access the JSON value of the QJsonObject.
This is what I've tried so far:
// Contains the whole API as QString...
QString data = QString(reply->readAll());
// Reads the JSON as QJsonDocument...
QJsonDocument jsonResponse = QJsonDocument::fromJson(data.toUtf8());
// Reads the JSON as QJsonObject...
QJsonObject jsonObject = jsonResponse.object();
Now I have my object well prepared, but trying to access the values of the JSON somehow fails:
// This returns an empty string ""!?!
qDebug() << jsonObject.value("success").toString();
Well, maybe I got the keys wrong:
// Let's check the keys...
QStringList stringList = jsonObject.keys();
for (QStringList::Iterator it = stringList.begin(); it != stringList.end(); ++it)
{
// This returns "success" and "return" - huh!?!
qDebug() << *it;
}
OK, the keys are veryfied, why is it not working?
// Let's check the values by using the keys directly...
for (QStringList::Iterator it = stringList.begin(); it != stringList.end(); ++it)
{
// This returns empty strings "" and "" - now what?!?
qDebug() << jsonObject.value(*it).toString();
}
This again, makes no sense at all. I can't see why I can not access the value of the JSON object by the keys. Any idea?
I tried exactly the same code on other JSON APIs (for example this one) without any issues. I am totally stuck here.
Here's my solution for Qt5 Json parsing the Cryptsy API.
QEventLoop loopEvent;
QNetworkAccessManager namMNGR;
QObject::connect(&namMNGR, SIGNAL(finished(QNetworkReply*)), &loopEvent, SLOT(quit()));
QNetworkRequest req(QUrl(QString("http://pubapi.cryptsy.com/api.php?method=singlemarketdata&marketid=%1").arg(marketID)));
QNetworkReply *reply = namMNGR.get(req);
loopEvent.exec();
//Json API parsing begins.
QString jsonSTR = reply->readAll();
if (!(reply->error() == QNetworkReply::NoError)) {
delete reply; //API Connection Problem.
}
QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonSTR.toUtf8());
QJsonObject obj1 = jsonDocument.object();
QJsonValue val1 = obj1.value(obj1.keys().first());
QJsonObject obj2 = val1.toObject();
QJsonValue val2 = obj2.value(obj2.keys().first());
QJsonObject obj3 = val2.toObject();
QJsonValue marketDataValue = obj3.value(obj3.keys().first());
QJsonObject marketDataObject = marketDataValue.toObject();
QJsonArray sellordersArray = marketDataObject["sellorders"].toArray();
Have you managed to get Authenticated POST API data from Qt5? I'm trying to figure out how to do it.

Creating a QVariantMap in Qt with strings

Apologies for asking something this trivial but I just can't seem to get it right so I guess I've completely misunderstood everything I thought I knew about memory management.
I have a function that parses a network reply for some data and it looks like this:
// Call from another function
QVariantMap *mappedResult = handleReply(reply);
...
// Function
QVariantMap *handleReply(QNetworkReply *reply) {
QVariantMap *result = new QVariantMap;
QVariant testvalue = new QVariant("testvalue");
result->insert("testkey", testvalue);
if (reply->error() > 0) {
qDebug() << "Error number = " + reply->errorString();
QVariant variant = QVariant.fromValue(reply->errorString());
result->insert("error", variant);
} else {
QJsonDocument jsonResponse = QJsonDocument::fromJson(jsonString.toUtf8());
QJsonObject jsonResponseObject = jsonResponse.object();
*result = jsonResponseObject.toVariantMap();
}
return result;
}
If there is no error, the result is parsed fine by the built in toVariantMap function. When there is an error however, I would like to create an entry in the result that is sent back from the function. As you can see in the function, I'm trying to create QVariants from Strings in two different ways.
The first approach gives an error like this:
C:\Qt\5.2.0\mingw48_32\include\QtCore\qvariant.h:466: error: 'QVariant::QVariant(void*)' is private inline QVariant(void *) Q_DECL_EQ_DELETE;
^
The second approach like this:
[PATH] error: expected primary-expression before '.' token QVariant variant = QVariant.fromValue(reply->errorString());
I've also tried setting the values like this:
result->insert("testkey", "testvalue");
result->insert("error", reply->errorString());
The last approach doesn't give compile errors but the result variable in the return statement cannot be inspected in the debugger and as soon as the return statement is executed the application crashes with memory problems indicating I'm not using "new" properly.
"Error accessing memory address 0x...".
If someone with at least a little knowledge could help me sort out how to perform this simple task, I would be very greatful. How can I return a QVariantMap from my function with custom strings as key/value pairs?
Cheers.
I would write your function in the following way (with fixes):
QVariantMap *handleReply(QNetworkReply *reply) {
QVariantMap *result = new QVariantMap;
QVariant testvalue("testvalue"); // <- fixed here
result->insert("testkey", testvalue);
if (reply->error() > 0) {
qDebug() << "Error number = " + reply->errorString();
QVariant variant(reply->errorString()); // <- fixed here
result->insert("error", variant);
} else {
QJsonDocument jsonResponse = QJsonDocument::fromJson(jsonString.toUtf8());
QJsonObject jsonResponseObject = jsonResponse.object();
*result = jsonResponseObject.toVariantMap();
}
return result;
}
However it is still unclear, why do you need to work with a pointer to the variant map instread of passing it by value?

How to use Google Translate API With c++

I'm a beginner in C++ and using Google task API.
How do I write a C++ program that accepts a word, then invokes Google Translate to translate it from English to French, then saves the resulted page to a local file?
For example, if the user inputs "river", the program should invoke Google Translate to translate into French, the resulting page is:
http://translate.google.com/#en|fr|River%0A
This page should be saved.
I read the official documentation through fully: http://code.google.com/apis/language/translate/v2/getting_started.html
but I couldn't understand how to using REST and I'm not familiar with JSON or AJAX.
You cannot use JSON objects straight in C++.
JSON = JavaScript Object Notation
You need to spawn/create something which can parse such objects. For example I've used QNetworkManager in Qt (in C++) to send build javascript and send requests to google APIs. The result would be a JSON object which I had to parse and either display in a browser (which I made in c++) or parse the results into a c++ class and process it differently (do some calculations with it).
If you just need the data, you can request XML instead of JSON and then you can use a standard XML parser to extract the translated word.
EDIT 1:
Google in their example uses:
https://www.googleapis.com/language/translate/v2?key=YOUR-API-KEY&source=en&target=de&q=words+to+translate
This translate from english (en) to german (de). The words to translate are: "words to translate".
Now build an HTTP request in C++ with this URL as the data. Send that with some network manager or sockets and wait for a reply back. Google will give you back data.
I seen this codes below somewhere but I don't remember where, anyway try this:
QString YourClass::translate(QString keyword, QString from, QString to)
{
//Translate URL
QString url = QString("http://translate.google.com/translate_a/t?client=t&text=%0&hl=%1&sl=%2&tl=%1&multires=1&prev=enter&oc=2&ssel=0&tsel=0&uptl=%1&sc=1").arg(keyword).arg(to).arg(from);
QNetworkAccessManager manager;
QNetworkRequest request(url);
QNetworkReply *reply = manager.get(request);
//Get reply from Google
do {
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
} while(!reply->isFinished());
//Convert to string
QString translation(reply->readAll());
reply->close();
//Free memory
delete reply;
//Remove [[[" from the beginning
translation = translation.replace("[[[\"", "");
//Extract final translated string
translation = translation.mid(0, translation.indexOf(",\"") - 1);
return translation;
}
someone advise me to use libcurl, I will try and see.
You need some kind of HTTP library. I second most of what Adrian said, but here's some (incomplete) Qt code which should give you an idea.
namespace {
const QString API_KEY = /* TODO */;
}
MyQObject :: MyQbject ()
: m_manager (new QNetworkAccessManager (this))
{
connect(manager, SIGNAL (finished (QNetworkReply *)),
this, SLOT (reply_finished (QNetworkReply *)));
}
void MyQObject :: fetch_translation (
QString words,
void (*on_receive)(const QString &))
{
// Let's assume asynchronous but non-concurrent requests.
m_on_receive = on_receive;
QString request =
"https://www.googleapis.com/language/translate/v2"
"?key=%1&source=en&target=de&q=%2";
// May want to url-encode 'words' first.
m_manager -> get (QUrl (request .arg (API_KEY) .arg (words));
}
void MyQObject :: reply_finished (QNetworkReply * reply)
{
m_on_receive (reply -> readAll ());
}
// ...
{
my_q_object -> translate ("hello, world", [](const QString & s) {
qWarning () << "translation is: " << s;
});
}