QScriptEngine, converting JSON data to QVariants
-
wrote on 14 Mar 2011, 23:05 last edited by
Hi All,
I'm attempting to read some objects from pre-existing JSON data. I'm running in to trouble when the data is non-trivial. The actual data I need to read is a lot more complex than the samples below, but they demonstrate the problem! I expect this is due to my misreading of the documentation (or misunderstanding of the concepts!) but anyway …
According to http://doc.qt.nokia.com/4.7/qscriptvalue.html#toVariant , "The array is converted to a QVariantList. Each element is converted to a QVariant, recursively; cyclic references are not followed." - so why when I try to read a simple 2-element array (which I expect to come out as a list) is each element of the QVariantList not the appropriate type of qvariant (string), but instead a "usertype" variant, seemingly with no content?
With the single string, the output from the code fragment below is:
valid
type: QVariant::QString
"a"With the other example data (commented out below), though, an array of two strings, the output is:
list
type: QVariant::UserType
""
type: QVariant::UserType
""(apologies, not quite a complete ready-to-compile sample, lifted from a larger project, but almost complete, just needs the right #includes I think!)
@void debugPrintVariant (QVariant const & v)
{
if (! v. isValid ()) {
qDebug () << "invalid";
}
if (QVariant:: List == v. type ()) {
qDebug () << "list";
for (QList <QVariant>:: const_iterator i = v.toList (). begin (); i != v. toList (). end (); ++ i)
debugPrintVariant (*i);
} else if (QVariant:: Map == v. type ()) {
qDebug () << "map";
for (QMap <QString, QVariant>:: const_iterator i = v. toMap (). begin (); i != v. toMap (). end (); ++ i) {
qDebug () << "Key: " << i. key ();
debugPrintVariant (i. value ());
}
} else {
qDebug () << "type: " << v. type ();
qDebug () << v. toString ();
}
}void main () {
// This one works OK
QString jsonScript = "{"items": "a"}";
// This one, each list element is "user type", instead of string - how do I get at the data?
//QString jsonScript = "{"items": ["a", "b"]}";QScriptEngine se;
QScriptValue sv = se.evaluate ("JSON.parse").call(QScriptValue(), QScriptValueList() << jsonScript);
// Alternative parsing method, same result
//QScriptValue sv = se. evaluate ("(" + jsonScript + ")");QVariant rootVariant = sv. property("items"). toVariant ();
debugPrintVariant (rootVariant);
}@ -
wrote on 15 Mar 2011, 05:00 last edited by
You're iterating over the values wrong. The QVariant::toList() and QVariant::toMap() functions return a new list or map with each call. You can't compare iterators from the first call of toList() with iterators from the second call of toList(). Change it to
@
QList<QVariant> list = v.toList();
for (QList<QVariant>::const_iterator i = list.begin(); i != list.end(); ++i)
debugPrintVariant(*i);
@or better, use foreach
@
foreach (QVariant const &i, v.toList())
debugPrintVariant(i);
@ -
wrote on 15 Mar 2011, 06:37 last edited by
Note that if you just want to parse JSON, you can do so without using QtScript. Take a look at QJSON, for instance.
-
wrote on 15 Mar 2011, 09:35 last edited by
Thanks for quick and accurate response Bradley, I completely missed that, forgot I was actually transforming the data not just taking a view of it. D'oh.
Using JSON.parse in this way now works well. Are there any performance or other considerations that mean I should prefer the "JSON.parse" or "QScriptEngine.evaluate" approach?
-
wrote on 15 Mar 2011, 09:49 last edited by
[quote author="gallafent" date="1300181725"]Using JSON.parse in this way now works well. Are there any performance or other considerations that mean I should prefer the "JSON.parse" or "QScriptEngine.evaluate" approach?[/quote]
I seem to remember that the latter is unsafe. It might execute anything, while JSON.parse should be safe. You should not trust the data you get from outside, so just executing it is probably a bad idea. You should check this though, as this is from a vague memory on the topic. -
wrote on 15 Mar 2011, 10:01 last edited by
Good point Andre, thanks.
Much of the data is packaged with the app, and so "safe", but some will indeed come down the wire, so your point about the extra safety provided by using the JSON.parse approach is certainly applicable!
1/6