I have a QMap object and I would like to convert it to JSON. I am confused how I would accomplish this.
I read QT documentation saying that I can use QDataStream to convert QMap to JSON, but QDataStream seems to convert files: http://doc.qt.io/qt-4.8/datastreamformat.html
// c++
QMap<QString, int> myMap;
It would be easiest to convert the map to QVariantMap which can automatically be converted to a JSON document:
QMap<QString, int> myMap;
QVariantMap vmap;
QMapIterator<QString, int> i(myMap);
while (i.hasNext()) {
i.next();
vmap.insert(i.key(), i.value());
}
QJsonDocument json = QJsonDocument::fromVariant(vmap);
The same thing can be used to create a QJsonObject if you want, via the QJsonObject::fromVariant() static method. Although for QJsonObject you can skip the conversion to variant map step and simply populate the object manually as you iterate the map:
QMap<QString, int> myMap;
QJsonObject json;
QMapIterator<QString, int> i(myMap);
while (i.hasNext()) {
i.next();
json.insert(i.key(), i.value());
}
If you are using Qt 5.5 or higher you could use QJsonDocument::fromVariant, your map could be converted easily to a QVariantMap. If not, try QJson
For your purpose, you are looking for QMAP serialization, see this link: Serialization Qt. Try to set up the constructor with a QByteArray, something like this:
QByteArray serializeMap(const QMap<QString, int>& map) {
QByteArray buffer;
QDataStream stream(&buffer, QIODevice::WriteOnly);
out << map;
return out;
}
That's, will serialize your map in a QByteArray wich could be easily converted to a QString or std::string.
Related
As part of parsing a JSON response, we are traversing a tree of QVariantMaps. To my understanding, we are creating a copy at each level by calling QVariant::toMap() or qvariant_cast<QVariantMap>(). I would like to optimize this process however I can.
QString parse (QVariant input) {
QVariantMap map = input.toMap();
QVariant innerValue = map.value("key");
QVariantMap subMap = innerValue.toMap();
QVariant desiredValue = subMap.value("key2");
return desiredValue.toString();
}
Can we avoid copying each map by directly referencing the underlying value inside the QVariant? I assume that we would need a pointer, something like the following:
QString parse (QVariant input) {
// Assuming we know that input is a map
QVariantMap* map = getVariantPointer<QVariantMap*>(input);
QVariantMap* subMap = getVariantPointer<QVariantMap*>(map->value("key"));
return getVariantPointer<QString*>(subMap->value("key2"));
I have a QVariant with userType QVariantList and the exact format looks like this when i qDebug the qvariant
QVariant(QVariantList, (QVariant(QVariantMap, QMap(("name", QVariant(QString, "UK English Female"))))
I want QString, "UK English Female" from the variant how can i get that i have already tried QVariant.toStringList() but the stringlist is empty.
Thanks.
From what is shown as a debug output, I presume it was produced in a similar manner:
QVariantMap map;
map.insert("name", QVariant("UK English Female"));
qDebug() << QVariant(QVariantList{QVariant(map)});
and as a result you have a string data, which is burried relatively deep in a sequence of containers.
So, how to get there?
As a whole you have a QVariant holding a QVariantList with a single QVariant value, which in turn is a QMap. The map has a key name of type QVariant holding a QString. Chaining the necessary conversions, we end up with:
qDebug() << myVar.value<QVariantList>().first().toMap().value("name").toString();
assuming the whole thing is held in QVariant myVar;.
I am trying to learn how to use JSON and the Qt JSON classes. For example I wnat to create a simple QJsonDocument, save it to a file, load it into a different QJsonDocument and compare results.
I managed to create a QJsonDocument. However there is no simple command in the QJsonDocument interface to save it to a file. The same goes for loading the document from a file.
#include <QJsonObject>
#include <QJsonDocument>
#include <QVariant>
int main()
{
QVariantMap map;
map.insert("integer", 1);
map.insert("double", 2.34);
map.insert("bool", QVariant(true));
map.insert("string", "word");
QJsonObject object = QJsonObject::fromVariantMap(map);
QJsonDocument document;
document.setObject(object);
// ?? save document to file
// ?? load file to document
return 0;
}
This answer shows how to load the document by
reading to a QFile
converting QFile to a QString
converting the QString to a QByteArray
constructing the QJsonDocument from the QByteArray
Is there a more straightforward way to do this?
Personally, I think that code [that you linked to] looks a bit messy. Warning: head compiled code follows.
QJsonDocument loadJson(QString fileName) {
QFile jsonFile(fileName);
jsonFile.open(QFile::ReadOnly);
return QJsonDocument().fromJson(jsonFile.readAll());
}
void saveJson(QJsonDocument document, QString fileName) {
QFile jsonFile(fileName);
jsonFile.open(QFile::WriteOnly);
jsonFile.write(document.toJson());
}
This may not be perfect: it assumes QFile instead of QIODevice, but if you're dealing with only local files maybe it won't matter. You can then use these functions instead of repeating the Json load/save code everytime you need to load/save Json.
No need for converting to string and back. With QSettings and QVariant classes you can easily do that. Create QVariant object from QJsonDocument and save it with QSettings. Look at functions QJsonDocument::fromVariant and QJsonDocument::toVariant. Combine them with QSettings class and specifically void QSettings::setValue ( const QString & key, const QVariant & value ) method, that works well with QVariant and that's it.
Also QSettings class has this constructor QSettings::QSettings ( const QString & fileName, Format format, QObject * parent = 0 )
that would allow you to set path to the file - fileName variable
Is there a way to have multiple values for each key, stored in a human-readable (no binaries) .ini file, using QSettings?
Something that could look like:
key_1=value_1,value2
key_2=value_1
...
Yes, you should use QStringList type:
QStringList list;
list << "value_1" << "value2";
settings.setValue("key_1", list);
Output:
key_1=value_1, value2
Items that contains , will be quoted using "...".
Well from depends how you want to access it, you could use
QVariant value ( const QString & key, const QVariant & defaultValue = QVariant() ) const
in which you would be able to insert a QVariantList.
But i see there is a group format.
http://doc.qt.digia.com/4.6/qsettings.html#childGroups
After reading Save QList<int> to QSettings, I'm tring to do the same with QMap<QString,int>. I would like the configuration file to look like this:
1111=1
2222=3
4444=0
But I'm getting a compilation error:
Q_DECLARE_METATYPE(QMap<QString,int>)
Warning C4002: too many actual parameters for macro 'Q_DECLARE_METATYPE'
ConfigSettings.h(5) : error C2976: 'QMap' : too few template arguments
The error message you're getting is caused by the fact that the preprocessor doesn't know about templates. So it's parsing that macro call is if it had two arguments - QMap<QString and int>, which makes no sense.
To save the data as you want it, you're better of serializing it yourself to your QSettings. Something like this for writing:
settings.beginGroup("Whatever");
QMap<QString, int>::const_iterator i = map.constBegin();
while (i != map.constEnd()) {
settings.setValue(i.key(), i.value());
++i;
}
settings.endGroup();
To read the settings, use the same approach with the help of the childKeys() function.
settings.beginGroup("Whatever");
QStringList keys = settings.childKeys();
foreach (QString key, keys) {
map[key] = settings.value(key).toInt();
}
settings.endGroup();
Like Mat said, the error is caused by the preprocessor not understanding templates. However, you can easily fix this via a simple typedef.
typedef QMap<QString,int> QIntMap
Q_DECLARE_METATYPE(QIntMap)
QSetting accept QVariant type to pass into setValue method, so it means that you can store QMap<QString, QVarint> map directly to settings
// Store
QMap<QString, QVariant> storeMap;
QMapIterator it(myMap);
// iterate through the map to save the values in your chosen format
while(it.hasNext())
{
storeMap[it.key()] = QVariant(it.value());
it.next();
}
settings.setValue("myKey", storeMap);
..
// Read
QMap<QString, QVariant> readMap = settings.value("myKey").toMap();
QMapIterator it(readMap);
while(it.hasNext())
{
myMap[it.key()] = it.value().toInt();
it.next();
}
I understand the accepted answer, but I think the original question was how to store the QMap. It devolved into how to make the compiler behave.
QSettings mySettings...
QMapIterator it(myMap);
// iterate through the map to save the values in your chosen format
while(it.hasNext())
{
it.next();
mySettings.setValue(it.key(), it.value());
}
If however you wish to store this along with a bunch of other settings or data structures, you might consider using "beginGroup()" and "endGroup()" to group a bunch of different data structures into one file. Very tidy and readable.