Search code examples
qtqtnetwork

Trouble with QJsonArray


In my Console Project I have 4 functions: Response, AddDataToList, Request and main.

In main function chars is a Vector containing characters a-z. manager, doc, array and list are variables to be used in Request function along with the elements of chars. In the first for loop a single character (eg. a,b,c,…,z) from chars is passed to Request and in the following nested for loop two characters (eg. aa,ab,ac,…,zz) are passed to Request.

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QVector<char> chars;
    for (int i = 97; i < 123; i++) chars.push_back((char)i);

    QNetworkAccessManager manager;
    QJsonDocument doc;
    QJsonArray array;
    QVector<QString> list;
    int count = chars.count();

    for (int i = 0; i < count; i++) {
        Request(manager, QString(chars[i]), doc, array, list);
        for (int j = 0; j < count; j++)
            Request(manager, QString("%1%2").arg(chars[i]).arg(chars[j]), doc, array, list);
    }

    qDebug() << "Total: " + QString::number(list.count());
    return a.exec();
}

In Request those characters are used as querystring in the url that is passed to Response function to get json array and each element of array is then added to the Vector named list in AddDataToList function.

void Request(QNetworkAccessManager &manager, QString &queryString, 
         QJsonDocument &doc, QJsonArray &array, QVector<QString> &list) 
{
    QUrl url =QString("http://www.icab.org.bd/icabweb/firmCompanyAudited/geJsonAuditedFirm?term=%1").arg(queryString);
    Response(manager.get(QNetworkRequest(url)), doc, array);
    AddDataToList(list, array);
}

void Response(QNetworkReply *reply, QJsonDocument &doc, QJsonArray& array) 
{
    QEventLoop loop;
    QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    loop.exec();
    doc = QJsonDocument::fromJson(reply->readAll());
    delete reply;
    array = doc.array();
}

void AddDataToList(QVector<QString> &list, QJsonArray &array) 
{
    int count = array.count();
    for (int n = 0; n < count; n++) list.append(array[n].toString());
}

Last line of the main writes the number of elements in the list and I expected to get same number each time it runs, but the number was:

19793, 19703, 19791, etc.

reply->error() always gives NoError. Where is the problem?


EDIT:


I also have written equivalent code in C# where I had to use Newtonsoft.Json's DeserializeObject method in a try-catch in order to complete the loop. Result of 5 consecutive test sessions was:

Test Session: 0
19793  item found
0 item in error List
====================================================

Test Session: 1
ev : Unexpected character encountered while parsing value: <. Path '', line 0, position 0.
yy : Unexpected character encountered while parsing value: <. Path '', line 0, position 0.
19743  item found
2 item in error List
====================================================

Test Session: 2
cm : Unexpected character encountered while parsing value: <. Path '', line 0, position 0.
jv : Unexpected character encountered while parsing value: <. Path '', line 0, position 0.
nl : Unexpected character encountered while parsing value: <. Path '', line 0, position 0.
19737  item found
3 item in error List
====================================================

Test Session: 3
uk : Unexpected character encountered while parsing value: <. Path '', line 0, position 0.
19743  item found
1 item in error List
====================================================

Test Session: 4
lk : Unexpected character encountered while parsing value: <. Path '', line 0, position 0.
19768  item found
1 item in error List
====================================================

May I get somewhat similar error in my Qt Response function when I call: QJsonDocument::fromJson(reply->readAll()) or doc.array()?


I guess the problem is in doc = QJsonDocument::fromJson(reply->readAll()). It assigns <html> in doc in some cases.

Why does it send <html> instead of json?


Solution

  • I got curious about your problem and added your code to my test application.

    I needed to do one change to get you code compiled with gcc. You were passing temporary object as a query string. Add const to QString &queryString in Request function. I guess you are using MS compiler which is not as strict with this...

    error: invalid initialization of non-const reference of 
    type ‘QString&’ from an rvalue of type ‘QString’
        Request(manager, QString(chars[i]), doc, array, list);   
    

    I also added logging to Request

    qDebug() << "queryString:" << queryString;
    

    and also to AddDataToList

    void AddDataToList(QVector<QString> &list, QJsonArray &array)
    {
        int count = array.count();
        qDebug() << "count:" << count;
        for (int n = 0; n < count; n++)
        {
            QString appendString = array[n].toString();
            qDebug() << "index:" << n << "appendString:" << appendString;
            list.append(appendString);
        }
    }
    

    Then I started testing. I used shorter array of chars by changing integers to 110 -> 119 which lead to query strings n,nn, -> vu,vv. I directed output to a file on each test round so I could analyze the results afterwards.

    I got result 2984 over 10 times. During the testing session of about half an hour I got two results that differed. I compared the log files and noticed that sometimes the server returned empty response for some query strings in differing results. The count of result 2984 in parenthesis.

    I got result 2816 once:

    queryString: "nr"
    count: 0 (18)
    queryString: "ns"
    count: 0 (50)
    queryString: "nt"
    count: 0 (50)
    queryString: "nu"
    count: 0 (50)
    

    I got result 2934 once:

    queryString: "or"
    count: 0 (50)
    

    I would say it's a server problem.

    Addition to EDIT part of the question:

    You don't get as detailed error output but anyway it's caught like this:

    QJsonParseError e;
    doc = QJsonDocument::fromJson(reply->readAll(), &e);
    if ( e.error != QJsonParseError::NoError )
    {
        qWarning() << "Json parse error:" << e.errorString().toLatin1().data();
    }
    

    Here is what I got from parsing:

    queryString: "uy"
    Json parse error: illegal value
    count: 0
    

    See more details about QJsonParseError Class from here.

    Note: There is no point of calling QCoreApplication::exec() and entering the main event loop in your current implementation.