QT——JSON解析

一些相关知识的链接:

有关JOSN相关的基础知识:JSON基础
有关QT中JSON的操作:QT中JSON的操作
一个在线工具,可以进行JSON格式化分析的网址:JSON格式化


如何从网络中轻松得到JSON数据?
可以通过访问心知天气的相关API,心知天气就会给我们返回一串JSON数据。例如在浏览器中打开以下网址(将下面的key值和location值换掉):

https://api.seniverse.com/v3/weather/daily.json?key=你在心知天气中的私钥&location=成都&language=zh-Hans&unit=c&start=0&days=5


然后就会返回如下格式的JSON数据:
在这里插入图片描述

从 Qt 5.0 开始提供了对 Json 的支持,我们可以直接使用 Qt 提供的 Json 类进行数据的组织和解析。相关的类常用的主要有四个,具体如下:

JSON类功能介绍
QJsonDocument提供一种对JSON文档进行读和写的方法 ,比如将JSON格式的字符串转化为可以操作的JSON文档类。
QJsonObject封装了JSON对象。
QJsonArray封装了JSON数组。
QJsonValue封装了JSON支持的数据类型。

1、QT中JSON解析的步骤

先打一剂预防针:JSON解析是一个比较繁琐的过程,开始上手需要一定的耐心去学习。

JSON数据是由对象、数组、数据(键值对)封装而成。

现假设我们解析的JSON数据如下所示,最终我们要得到的是三天内的天气情况

{
  "results": [
    {
      "location": {
        "id": "WM6N2PM3WY2K",
        "name": "成都",
        "country": "CN",
        "path": "成都,成都,四川,中国",
        "timezone": "Asia/Shanghai",
        "timezone_offset": "+08:00"
      },
      "daily": [
        {
          "date": "2022-01-08",
          "text_day": "雾",
          "code_day": "30",
          "text_night": "阴",
          "code_night": "9",
          "high": "10",
          "low": "6",
          "rainfall": "0.00",
          "precip": "0.09",
          "wind_direction": "西南",
          "wind_direction_degree": "225",
          "wind_speed": "8.4",
          "wind_scale": "2",
          "humidity": "95"
        },
        {
          "date": "2022-01-09",
          "text_day": "阴",
          "code_day": "9",
          "text_night": "小雨",
          "code_night": "13",
          "high": "10",
          "low": "6",
          "rainfall": "0.12",
          "precip": "0.38",
          "wind_direction": "无持续风向",
          "wind_direction_degree": "",
          "wind_speed": "8.4",
          "wind_scale": "2",
          "humidity": "97"
        },
        {
          "date": "2022-01-10",
          "text_day": "多云",
          "code_day": "4",
          "text_night": "晴",
          "code_night": "1",
          "high": "13",
          "low": "3",
          "rainfall": "0.00",
          "precip": "0.09",
          "wind_direction": "无持续风向",
          "wind_direction_degree": "",
          "wind_speed": "3.0",
          "wind_scale": "1",
          "humidity": "95"
        }
      ],
      "last_update": "2022-01-08T08:00:00+08:00"
    }
  ]
}

看完之后一头雾水?不存在的,我带你一步步扒开它的外套。
1、先看整体框架是如何构成的
最外层是一个对象(对象1),然后对象1中只有一个数据(即键值对)。通过该类下的“result”键就可以获取到值(数组1),数组里面只有一个数据(对象2),对象2中含有三个数据,都是由是三个键值对组成。

{		//对象1
  "results": [				//数组1
    {	//对象2
    	"location"{位置信息},
    	"daily": [ {第一天的天气信息} , {第二天的天气信息} , {第三天的天气信息} ],		//数组2
    	"last_update": "2022-01-08T08:00:00+08:00"
    }
  	]
}

2、用JSON解析时,如何获取键为daily所对应的值呢?

  • 先进入最外层的对象1;
  • 通过键result查找对应的值,即数组1;
  • 从数组中获取到下标为0的数据——对象2;
  • 在对象2中,通过键dialy获取对应的值——数组2;
  • 数组2中包含三个对象,可以通过遍历分别得到每个对象,并从对象中根据键值对的方法,获取到天气信息。

:上面的分析很重要哦,应为编程时,就是按照上面的思路进行编写的。如果看不太懂,可以结合到下面给出的具体代码对比着看。

//需要导入的头文件
#include "QJsonDocument"
#include "QJsonObject"
#include "QJsonArray"
#include "QJsonValue"
#include "QJsonParseError"

1、先用QJsonDocument类下的一个静态方法fromJson()将获取到的JSON数据转化为JSON文档。例如:

QJsonParseError jsonParseError;     //创建一个JSON错误类,用于接收JSON解析错误的信息
QJsonDocument jsonDocument = QJsonDocument::fromJson(data1,&jsonParseError);	//data1为获取到的JSON数据

2、从传回的JSON错误类中,判断是否出错。

if((jsonParseError.error != QJsonParseError::NoError)&&(jsonDocument.isNull()))
    {
        qDebug()<< "JSON格式错误";
        return;
    }

3、将JSON文档类进行转化为相应的JSON类型(有JOSN对象和JSON数组)。

这个转化要根据串回来的JSON数据格式确定,比如传回来的JOSN数据最外层是“[ ]”(即JSON数据是由中括号扩起来的,表明是一个数组),则转化为JOSN数组类型;如果传回来的JOSN数据最外层是“{ }”(即传回来的JSON数据最外层是大括号,表明是一个对象),则转化为JSON对象。

从上面给出的JSON数据中可以看出,最外层为大括号,表示返回的是一个对象,所以这里第一步就要将JSON文档转化为一个JSON对象,然后再操作。

QJsonObject rootObject = jsonDocument.object();     //将文档对象中的数据转化为JSON对象,这里的JSON数据的最外层为对象;最外层若为数组,则要用jsonDocument.array()

4、对最外层的这个对象,一步一步的扒皮,然后获取到键“daily”所对应的值。

QJsonArray resultArray = rootObject.value("results").toArray();     //得到键为“result”所对应的值。观察知道这个值为数组,所以将其转换为JSON数组类型
QJsonObject resultArrayObject = resultArray.at(0).toObject();       //获取到数组下标0对应的数据,并将类型转化为JSON对象
QJsonArray dailyArray = resultArrayObject.value("daily").toArray(); //获取到键为“daily”所对应的值,并将类型转化为JSON数组

注: 在解析过程中,对每次得到的JSON数据,都要更转化为后面对应的JSON数据类型,是数组就转化为数组,是对象就转化为对象。

5、对这个JSON数组进行遍历,获取到其中的每个对象,并在每个对象中,更具键值对获取到每天的天气信息。

for(int i=0;i<dailyArray.count();i++)   //对数组进行遍历
{
    QJsonValue dailyArrayObject = dailyArray.at(i);    //读取数组中第i个数据
    if(dailyArrayObject.type() == QJsonValue::Object)  //如果数组中的第i数据的类型是JSON类
    {
     QJsonObject dailyArrayObjectValue = dailyArrayObject.toObject();	//将数据转换为JSON类
     //在类中根据键获取对应值
     QJsonValue dateValue = dailyArrayObjectValue.value("date");   //获取时间,对应的键为“date”
     QJsonValue text_dayValue = dailyArrayObjectValue.value("text_day");   //获取白天天气,对应的键为“text_day”
     QJsonValue text_nightValue = dailyArrayObjectValue.value("text_night");   //获取晚上天气,对应的键为“text_night”
     QJsonValue highValue = dailyArrayObjectValue.value("high");   //获取最高温度,对应的键为“high”
     QJsonValue lowValue = dailyArrayObjectValue.value("low");   //获取最低温度,对应的键为“low”
     //将值转化为对应的类型,并保存在结构体中
     info[i].date = dateValue.toString();
     info[i].text_day = text_dayValue.toString();
     info[i].text_night = text_nightValue.toString();
     info[i].high = highValue.toString().toInt();
     info[i].low = lowValue.toString().toInt();

     //调试输出看看
     qDebug()<<"日期:"<<info[i].date;
     qDebug()<<"白天天气:"<<info[i].text_day;
     qDebug()<<"晚上天气:"<<info[i].text_night;
     qDebug()<<"温度范围:"<<info[i].low<<"℃-"<<info[i].high<<"℃";
	}
}
<think> 我们正在讨论如何使用Qt解析JSON数据。根据引用,Qt从5.0开始提供了对JSON的支持,主要使用四个类:QJsonDocument、QJsonObject、QJsonArray和QJsonValue。以下将详细介绍解析步骤和方法。 ### 一、Qt JSON解析核心类 根据引用[1][3][4],Qt JSON解析主要依赖以下类: 1. **QJsonDocument**:读写JSON文档的接口,可将JSON数据转换为可操作对象[^1][^4] 2. **QJsonObject**:封装JSON对象(键值对集合),键为字符串,值为JSON支持的类型[^3] 3. **QJsonArray**:封装JSON数组(值的有序列表)[^4] 4. **QJsonValue**:封装JSON支持的数据类型(包括字符串、数字、布尔值、数组、对象等)[^1] ### 二、JSON解析步骤 参考引用[1][4]的代码示例,标准解析流程如下: #### 1. 读取原始JSON数据 ```cpp // 从网络回复读取数据(示例见引用[4]) QByteArray data = replay->readAll(); // 或直接使用字符串(示例见引用[5]) QString str = "{\"name\":\"xiaotang\", \"age\":\"23\"}"; QByteArray data = str.toUtf8(); ``` #### 2. 转换为QJsonDocument 使用`QJsonDocument::fromJson()`解析原始数据: ```cpp QJsonParseError jsonError; // 错误信息对象 QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); // 检查解析错误 if(jsonError.error != QJsonParseError::NoError) { qDebug() << "JSON格式错误:" << jsonError.errorString(); return; } ``` #### 3. 判断文档类型并获取根对象 JSON文档有两种类型:对象(`{}`)或数组(`[]`): ```cpp if(jsonDoc.isObject()) { // 根节点是对象 QJsonObject rootObj = jsonDoc.object(); parseObject(rootObj); // 自定义解析函数 } else if(jsonDoc.isArray()) { // 根节点是数组 QJsonArray rootArray = jsonDoc.array(); parseArray(rootArray); // 自定义解析函数 } ``` ### 三、数据提取方法 #### 1. 解析JSON对象(QJsonObject) 引用[3][4]展示了对象解析: ```cpp void parseObject(const QJsonObject &obj) { // 检查键是否存在 if(obj.contains("Name")) { // 获取值并判断类型 QJsonValue nameValue = obj.value("Name"); if(nameValue.isString()) { QString name = nameValue.toString(); qDebug() << "Name:" << name; // 输出: Name: "Qt" } } // 直接取值(简化版) int year = obj["From"].toInt(); // 直接转换为int bool crossPlatform = obj["Cross Platform"].toBool(); } ``` #### 2. 解析JSON数组(QJsonArray) 引用[5]中的数组解析示例: ```cpp // 解析引用[5]中的chi数组 QJsonArray chiArray = rootObj["chi"].toArray(); for(int i = 0; i < chiArray.size(); i++) { QJsonObject item = chiArray[i].toObject(); QString a = item["a"].toString(); // 输出: 第一项"aa", 第二项"aaa" QString b = item["b"].toString(); // 输出: 第一项"bb", 第二项"bbb" } ``` ### 四、完整解析示例(引用[4]网络请求场景) ```cpp void MainWindow::replyFinished(QNetworkReply* replay) { if(replay->error() == QNetworkReply::NoError) { QByteArray data = replay->readAll(); QJsonParseError jsonError; QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); if(jsonError.error == QJsonParseError::NoError) { if(jsonDoc.isObject()) { QJsonObject rootObj = jsonDoc.object(); if(rootObj.contains("weatherinfo")) { QJsonValue weatherValue = rootObj.value("weatherinfo"); if(weatherValue.isObject()) { QJsonObject weatherObj = weatherValue.toObject(); // 转换为QVariantMap便于使用 QVariantMap weatherMap = weatherObj.toVariantMap(); QString city = weatherMap["city"].toString(); qDebug() << "城市:" << city; } } } } } } ``` ### 五、常见错误处理 1. **键不存在时的处理** ```cpp // 安全取值方法 if(obj.contains("key") && obj["key"].isString()) { QString value = obj["key"].toString(); } ``` 2. **类型转换失败** ```cpp QJsonValue value = obj.value("age"); if(value.isString()) { // 即使数字也可能被解析为字符串 bool ok; int age = value.toString().toInt(&ok); if(!ok) qDebug() << "age转换失败"; } ``` 3. **嵌套对象/数组访问** ```cpp // 访问深层数据:data.list[0].id if(rootObj.contains("data") && rootObj["data"].isObject()) { QJsonObject dataObj = rootObj["data"].toObject(); if(dataObj.contains("list") && dataObj["list"].isArray()) { QJsonArray listArray = dataObj["list"].toArray(); if(listArray.size() > 0 && listArray[0].isObject()) { QJsonObject item = listArray[0].toObject(); int id = item["id"].toInt(); } } } ``` > **关键点**:Qt JSON解析采用链式安全访问,必须逐层检查类型和键是否存在[^4]。 ### 六、JSON生成方法 引用[3]展示了如何构建JSON: ```cpp // 创建JSON对象 QJsonObject json; json.insert("Name", "Qt"); json.insert("From", 2016); json.insert("Cross Platform", true); // 添加数组 QJsonArray versions; versions.append(5.9); versions.append(5.12); versions.append(6.0); json.insert("Versions", versions); // 转换为文档 QJsonDocument jsonDoc(json); QString jsonString = jsonDoc.toJson(); // 生成JSON字符串 ``` ### 性能优化建议 1. **避免大文件解析阻塞UI线程**:网络请求或大文件解析使用`QCoreApplication::processEvents()`分块处理 2. **减少临时对象**:尽量使用`const QJsonObject&`传递引用 3. **二进制存储**:对重复使用的JSON数据,用`jsonDoc.toBinaryData()`保存为二进制格式加快加载 §§相关问题§§ 1. Qt中如何实现JSON数据与自定义对象的相互转换? 2. 如何处理JSON解析中的编码问题(如中文乱码)? 3. Qt网络请求(QNetworkAccessManager)如何与JSON解析结合使用? [^1]: QT——JSON解析 [^2]: QT Json解析方法 [^3]: Qt--解析Json [^4]: Qt解析Json的总结 [^5]: Qt解析JSON数据 </think> ### Qt JSON解析方法详解 根据引用内容,Qt从5.0开始提供原生JSON支持,主要使用以下四个核心类进行解析: #### 一、关键JSON解析类 | 类名 | 功能 | 示例代码 | |------|------|----------| | `QJsonDocument` | JSON文档读写入口 | `QJsonDocument::fromJson(data, &error)`[^4] | | `QJsonObject` | 封装JSON对象(键值对集合) | `json.insert("Name", "Qt")`[^3] | | `QJsonArray` | 封装JSON数组(有序值列表) | `QJsonArray versions = {5.9, 5.12, 6.0}` | | `QJsonValue` | 封装JSON支持的数据类型 | `if(obj["weatherinfo"].isObject())`[^4] | #### 二、标准解析流程 1. **准备原始数据** ```cpp // 从网络获取(引用[4]示例) QByteArray data = replay->readAll(); // 或直接定义字符串(引用[5]示例) QString str = R"({"name":"xiaotang", "age":23, "languages":["C++", "Python"]})"; ``` 2. **转换为JSON文档** ```cpp QJsonParseError jsonError; // 错误处理对象 QJsonDocument jsonDoc = QJsonDocument::fromJson(data.toUtf8(), &jsonError); if(jsonError.error != QJsonParseError::NoError) { // 检查格式错误 qDebug() << "JSON格式错误:" << jsonError.errorString(); return; } ``` 3. **获取根对象/数组** ```cpp if(jsonDoc.isObject()) { // 根节点是对象 QJsonObject rootObj = jsonDoc.object(); parseObject(rootObj); } else if(jsonDoc.isArray()) { // 根节点是数组 QJsonArray rootArray = jsonDoc.array(); parseArray(rootArray); } ``` 4. **递归解析嵌套结构** ```cpp void parseObject(const QJsonObject &obj) { // 获取字符串值 if(obj.contains("name")) { QString name = obj["name"].toString(); qDebug() << "Name:" << name; } // 获取嵌套对象 if(obj.contains("weatherinfo") && obj["weatherinfo"].isObject()) { QJsonObject weather = obj["weatherinfo"].toObject(); parseObject(weather); // 递归解析 } // 获取数组 if(obj.contains("languages") && obj["languages"].isArray()) { QJsonArray langArray = obj["languages"].toArray(); for(const QJsonValue &val : langArray) { qDebug() << "Language:" << val.toString(); } } } ``` #### 三、完整网络请求解析示例 基于引用[4]的增强实现: ```cpp void handleNetworkReply(QNetworkReply* reply) { if(reply->error() == QNetworkReply::NoError) { QByteArray data = reply->readAll(); QJsonParseError jsonError; QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); if(jsonError.error == QJsonParseError::NoError) { if(jsonDoc.isObject()) { QJsonObject root = jsonDoc.object(); if(root.contains("weatherinfo")) { QJsonObject weather = root["weatherinfo"].toObject(); // 安全提取数据 QString city = weather.value("city").toString("Unknown"); double temp = weather.value("temp").toDouble(0.0); qDebug() << city << "当前温度:" << temp << "℃"; } } } else { qWarning() << "JSON解析错误:" << jsonError.errorString(); } } else { qCritical() << "网络错误:" << reply->errorString(); } reply->deleteLater(); // 清理资源 } ``` #### 四、常见问题解决方案 1. **中文乱码处理** ```cpp // 设置全局编码(main函数中) QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")); ``` 2. **类型安全访问** ```cpp // 安全获取值(避免崩溃) int age = obj.value("age").toInt(-1); // -1表示默认值 if(age == -1) qWarning() << "age字段缺失或类型错误"; ``` 3. **动态键名处理** ```cpp QStringList keys = obj.keys(); for(const QString &key : keys) { QJsonValue val = obj.value(key); if(val.isString()) { qDebug() << key << ":" << val.toString(); } } ``` #### 五、性能优化建议 1. **避免深度嵌套**:JSON层级不宜超过5层 2. **使用二进制格式**:频繁读写时用`QJsonDocument::toBinaryData()` 3. **异步解析**:大文件使用`QtConcurrent::run()`在后台线程解析 4. **内存管理**:及时释放`QNetworkReply`对象(`deleteLater()`) > 最佳实践:对于超过1MB的JSON文件,建议使用流式解析器(如`QJsonStreamReader`)替代DOM解析[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

掏一淘哆啦A梦的奇妙口袋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值