Convert QJsonObject to Javascript object

2k Views Asked by At

As qt docs on QJSValue, QJsonObject ins't implicitly convertible to QJSValue, I want to call a javascript function with QJSEngine from C++, the arguments should be passed with QList<QJsValue> to call function of another QJSValue which holds the function itself.

The problem is one of my arguments is QJsonObject, until now i am supposed to convert it to text then calling and passing it to the javascript function that calls to JSON.parse for converting it to object, i am looking for a solution that lets me convert QJsonObject into QJSValue in C++ and call javascript function with object arguments instead of json text.

Currently the code is like something below

QJsonObject obj;
obj["1"] = QString("A");
obj["2"] = QString("B");

QJSValue func = myEngine.evaluate("(function(arg) { var obj = JSON.parse(arg); var res = obj[\"1\"] + obj[\"2\"]; return res; })");
QJSValueList args;
args << QString(QJsonDocument(obj).toJson());
QJSValue res = func.call(args);

I would like to have a function like QJSValue ConvertToQJSValue(QJsonObject object) something like this :

QJsonObject obj;
obj["1"] = QString("A");
obj["2"] = QString("B");

QJSValue func = myEngine.evaluate("(function(arg) { var res = arg[\"1\"] + arg[\"2\"];  return res; })");
QJSValueList args;
args << ConvertToQJSValue(obj);
QJSValue res = func.call(args);
3

There are 3 best solutions below

0
Mohammad Kanan On

Possibly, convert individual QJsonObject values to QJSValue using toScriptValue(), then concatenate them up to the QJSValueList .. and call func to append them up in one QJSValue.

QJSEngine myEngine;
QJsonObject obj;
obj["1"] = QString("A");
obj["2"] = QString("B");
obj["3"] = QString("C");

QJSValue func = myEngine.evaluate("(function() {var args = Array.prototype.slice.call(arguments); var res='';for(i=0; i<args.length; i++) {res += args[i]}; return res})");
QJSValueList args;
for (int i=0 ; i < obj.size(); i++){
    args << myEngine.toScriptValue(obj.value(obj.keys().at(i)));
}
QJSValue res = func.call(args);

I am not sure though if this is the right thing you should do, because you can get the QJSValue directly as an object,

QJSValue res = myEngine.newObject();
for (int i=0; i<args.length(); i++){
    res.setProperty(i,args[i]);
}

or a QJSValue array:

QJSValue objArray = myEngine.newArray(args.length());
for (int x=0; x< args.length();x++){
    objArray.setProperty(x,args[x]);
}
0
selbie On

I had a similar problem. I started going down the path of just walking the tree recursively from the QJsonValue and building a QJSValue from that.

QJSValue Convert(QJSEngine* engine, const QJsonValue& val)
{
    if (val.isBool())
    {
        return QJSValue(val.toBool());
    }
    else if (val.isString())
    {
        return QJSValue(val.toString());
    }
    else if (val.isDouble())
    {
        return QJSValue(val.toDouble());
    }
    else if (val.isNull())
    {
        return QJSValue(QJSValue::NullValue);
    }
    else if (val.isUndefined())
    {
        return QJSValue(QJSValue::UndefinedValue);
    }
    else if (val.isObject())
    {
        QJsonObject obj = val.toObject();
        QJSValue newobj = engine->newObject();
        for (auto itor = obj.begin(); itor != obj.end(); itor++)
        {
            QString key = itor.key();
            QJsonValue value = itor.value();
            QJSValue convertedValue = Convert(engine, value);
            newobj.setProperty(key, convertedValue);
        }
        return newobj;
    }
    else if (val.isArray())
    {
        QJsonArray arr = val.toArray();
        QJSValue newobj = engine->newArray(arr.size());
        for (int i = 0; i < arr.size(); i++)
        {
            QJsonValue value = arr[i];
            QJSValue convertedValue = Convert(engine, value);
            newobj.setProperty(i, convertedValue);
        }
        return newobj;
    }


    // ASSERT(FALSE && "This shouldn't happen");
    return QJSValue(QJSValue::UndefinedValue);

}

In the above code you could pass a QJsonObject or any other type of JSON node for conversion to a QJSValue.

I'm currently going with something closer to your original solution - just invoke JSON.parse from the engine:

QJSValue func = engine->evaluate("JSON.parse");
QJSValueList args;
args.append(jsonText); // jsonText is a QString or QJSValue string
QJSValue result = func.call(args);
return result;
0
Maxim Paperno On

As simple as QJSEngine::toScriptValue(const T &). T must be a QJsonObject or QJsonArray, not a QJsonDocument.

QJsonObject obj;
/// ...
QJSonDocument doc(obj);
QJSEngine engine;
QJSValue res;
if (doc.isObject()) 
  res = engine.toScriptValue(doc.object())
else if (doc.isArray())
  res = engine.toScriptValue(doc.array())
else
  res = engine.newErrorObject(
    QJSValue::TypeError, 
    "JSON was neither an object nor array.  Strange, right?"
  );