QScriptEngine, converting JSON data to QVariants
-
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);
}@ -
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);
@ -
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?
-
[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.