Введение
Работа с JSON в Qt строится на нескольких классах модуля QtCore: QJsonDocument, QJsonObject, QJsonArray и QJsonValue. С их помощью можно разобрать ответ веб-сервиса, загрузить конфигурацию или сохранить состояние приложения. В этой статье основное внимание уделено чтению. Разбор JSON включает проверку ошибок и типов, доступ к вложенным данным, обход объектов и массивов и изменение документа. О создании и сохранении файлов подробно рассказано в статье Запись в JSON в Qt.
Основные классы
QJsonDocument— полный JSON-документ, умеет разбирать текст и превращать данные обратно в текст;QJsonObject— объект из пар «ключ — значение»;QJsonArray— массив значений;QJsonValue— универсальный контейнер для любого значения JSON;QJsonParseError— описание ошибки разбора.
Пример 1: чтение JSON из строки
QString jsonString = R"(
{
"name": "Тестовая модель",
"version": 1,
"enabled": true,
"parameters": [1.0, 2.5, 3.75]
}
)";
QJsonDocument doc = QJsonDocument::fromJson(jsonString.toUtf8());
if (!doc.isNull() && doc.isObject()) {
QJsonObject obj = doc.object();
QString name = obj["name"].toString();
int version = obj["version"].toInt();
bool enabled = obj["enabled"].toBool();
QJsonArray params = obj["parameters"].toArray();
qDebug() << "Имя:" << name;
qDebug() << "Версия:" << version;
qDebug() << "Включено:" << enabled;
qDebug() << "Параметры:" << params;
}
Метод fromJson() принимает QByteArray в UTF-8. Если текст некорректен, возвращается пустой документ, и isNull() вернёт true. Корнем документа может быть как объект, так и массив, поэтому перед вызовом object() стоит проверить isObject().
Пример 2: чтение JSON из файла с проверкой ошибок
QFile file("data.json");
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << "Не удалось открыть файл:" << file.errorString();
return;
}
QJsonParseError parseError;
QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &parseError);
if (parseError.error != QJsonParseError::NoError) {
qWarning() << "Ошибка разбора JSON:" << parseError.errorString()
<< "в позиции" << parseError.offset;
return;
}
QJsonObject obj = doc.object();
Поле offset показывает, в каком месте текста найдена ошибка. Это сильно упрощает поиск лишней запятой или пропущенной кавычки.
Разбор JSON: проверка ключей и типов
Если ключа нет, оператор [] вернёт значение типа Undefined, а методы toString(), toInt() вернут пустую строку или ноль. Чтобы не перепутать отсутствующее значение с настоящим нулём, проверяйте ключ и тип явно:
if (obj.contains("version") && obj["version"].isDouble()) {
int version = obj["version"].toInt();
}
// Значение по умолчанию, если ключа нет
int timeout = obj["timeout"].toInt(30);
QString mode = obj.value("mode").toString("auto");
Для проверки типа есть методы isString(), isDouble(), isBool(), isArray(), isObject(), isNull() и isUndefined(). Все числа в JSON хранятся как double, поэтому для целых значений тоже используется isDouble().
Доступ к вложенным данным
// {"window": {"size": {"width": 800, "height": 600}}}
int width = obj["window"].toObject()["size"].toObject()["width"].toInt();
В Qt 6 цепочку можно записать короче, потому что QJsonValue тоже поддерживает оператор []:
int width = obj["window"]["size"]["width"].toInt();
Обход объектов и массивов
// Все ключи объекта
for (auto it = obj.constBegin(); it != obj.constEnd(); ++it)
qDebug() << it.key() << ":" << it.value();
// Элементы массива
QJsonArray users = obj["users"].toArray();
for (const QJsonValue &v : users) {
QJsonObject user = v.toObject();
qDebug() << user["name"].toString() << user["age"].toInt();
}
Изменение документа
Методы toObject() и toArray() возвращают копии. Поэтому изменённый вложенный объект нужно записать обратно:
QJsonObject window = obj["window"].toObject();
window["width"] = 1024;
obj["window"] = window; // без этой строки изменение потеряется
doc.setObject(obj);
Преобразование в QVariant
Если удобнее работать со стандартными типами Qt, документ можно превратить в QVariantMap или QVariantList:
QVariantMap map = obj.toVariantMap();
QStringList files = map["recentFiles"].toStringList();
Пример 3: формирование JSON
Создание документа выглядит зеркально чтению:
QJsonObject obj;
obj["status"] = "ok";
obj["timestamp"] = QDateTime::currentDateTime().toString(Qt::ISODate);
obj["parameters"] = QJsonArray{4.0, 5.5, 6.75};
QJsonDocument doc(obj);
qDebug().noquote() << doc.toJson(QJsonDocument::Indented);
Заключение
Работа с JSON в Qt удобна и не требует сторонних библиотек. При разборе всегда передавайте QJsonParseError в fromJson(), проверяйте наличие ключей и типы значений, а изменённые вложенные объекты записывайте обратно в родителя. Так программа будет устойчиво обрабатывать даже некорректные или неполные данные. Описание самого формата смотрите в статье JSON: назначение, структура и особенности формата.