赞
踩
JSON( JavaScript Object Notation,对象表示法) 是一种轻量级的数据交换格式。 它基于 ECMAScript 的一个子集。许多编程语言都很容易找到J SON 解析器和 JSON 库。 JSON 文本格式在语法上与创建 JavaScript 对象的代码相同。不同语言的不同 json 库对 JSON 标准的支持不尽相同,为了能让尽可能多的 JSON 库都能正常解析和生成 JSON ,定义 JSON 的规范很重要,推荐一个 JSON 规范《Google - JSON风格指南》。
在json.org 中介绍了 JSON 在各种语言中的应用,在 C/C++ 中比较常用的 JSON 库主要有以下几个:
nlohmann:是一个用于解析 JSON 的开源 C++ 库,口碑一流,使用非常方便直观,是很多 C++ 程序员的首选。
RapidJSON:腾讯员工开源的一个以高性能著称的 JSON 库,用的人也很多,缺点就是接口比较难用,不太友好。
cJSON:是一个超轻巧,携带方便,只有两个文件 cJSON.h 和 cJSON.cpp,简单的可以作为 ANSI-C 标准的 JSON 解析器,缺点是容易造成内存泄漏,也不支持线程安全。
QJson:是一个基于 Qt4 的开发包用来将 JSON 数据解析成 QVariant 对象,JSON 的数组将被映射为QVariantList 实例,而其他对象映射为 QVariantMap 实例,适合用在 Qt 开发平台上。
这里只简单讲解下 Qt 中对 JSON 的生成与解析,Qt5 以前的版本,可以使用 QJson 库,需要单独下载、编译,才能使用。到了 Qt5,提供了专门的 QJsonDocument 及其相关类来读和写 JSON 文档。
首先,JSON 的解析和构建都要包含如下头文件,下面一个个介绍下:
- #include <QJsonDocument>
- #include <QJsonArray>
- #include <QJsonObject>
QJsonDocument 类用于读和写 JSON 文档。
一个 JSON 文档可以使用 QJsonDocument::fromJson() 从基于文本的表示转化为 QJsonDocument, toJson(JsonFormat format = Indented) 则可以反向转化为文本,其中,format主要有两种格式,一种是人们可读的格式,一种是紧凑的格式。
已解析文档的有效性,可以使用 !isNull() 进行查询。
如果要查询一个 JSON 文档是否包含一个数组或一个对象,使用 isArray() 和 isObject()。包含在文档中的数组或对象可以使用 array() 或 object() 检索,然后读取或操作。
也可以使用 fromBinaryData() 或 fromRawData() 从存储的二进制表示创建来 JSON 文档。
QJsonArray 类封装了一个 JSON 数组。
JSON 数组是值的列表。列表可以被操作,通过从数组中插入和删除 QJsonValue 。
一个 QJsonArray 可以和一个 QVariantList 相互转换。可以使用 size() 来查询条目的数量,通过 insert() 在指定索引处插入值,removeAt() 来删除指定索引的值。
QJsonObject 类封装了一个 JSON 对象。
一个 JSON 对象是一个 “key/value” 列表,key 是独一无二的字符串,value 由一个 QJsonValue 表示。
一个 QJsonObject 可以和一个 QVariantMap 相互转换。可以使用 size() 来查询“key/value 对”的数量,通过 insert() 插入“key/value 对”, remove() 删除指定的 key。
QJsonValue 类封装了一个值。JSON 中的值有 6 种基本数据类型:
一个值可以由任何上述数据类型表示。此外,QJsonValue 有一个特殊的标记来表示未定义的值,可以使用 isUndefined() 查询。
值的类型可以通过 type() 或 isBool()、isString() 等访问函数查询。同样地,值可以通过 toBool()、toString() 等函数转化成相应的存储类型。
QJsonParseError 类用于在 JSON 解析中报告错误。
枚举 QJsonParseError::ParseError:该枚举描述 JSON 文档在解析过程中所发生的错误类型。
一个简单的 JSON 对象:
- {
- "Cross Platform": true,
- "From": 1991,
- "Name": "Qt"
- }
构建比较简单,由于是一个对象,只需要用 QJsonObject 即可:
- // 构建 JSON 对象
- QJsonObject jsonObj;
- jsonObj.insert("Name", "Qt");
- jsonObj.insert("From", 1991);
- jsonObj.insert("Cross Platform", true);
-
- // 构建 JSON 文档
- QJsonDocument document;
- document.setObject(jsonObj);
- QByteArray byteArray = document.toJson(QJsonDocument::Compact);
- QString strJson(byteArray);
-
- qDebug() << strJson;
解析如下:
- QJsonParseError jsonError;
- QJsonDocument doucment = QJsonDocument::fromJson(byteArray, &jsonError); // 转化为 JSON 文档
- if (!doucment.isNull() && (jsonError.error == QJsonParseError::NoError)) { // 解析未发生错误
- if (doucment.isObject()) { // JSON 文档为对象
- QJsonObject object = doucment.object(); // 转化为对象
- if (object.contains("Name")) { // 包含指定的 key
- QJsonValue value = object.value("Name"); // 获取指定 key 对应的 value
- if (value.isString()) { // 判断 value 是否为字符串
- QString strName = value.toString(); // 将 value 转化为字符串
- qDebug() << "Name : " << strName;
- }
- }
- if (object.contains("From")) {
- QJsonValue value = object.value("From");
- if (value.isDouble()) {
- int nFrom = value.toVariant().toInt();
- qDebug() << "From : " << nFrom;
- }
- }
- if (object.contains("Cross Platform")) {
- QJsonValue value = object.value("Cross Platform");
- if (value.isBool()) {
- bool bCrossPlatform = value.toBool();
- qDebug() << "CrossPlatform : " << bCrossPlatform;
- }
- }
- }
- }
注意:在转化为 QJsonDocument 后,首先需要根据 QJsonParseError 的值判定是否转化成功,然后在进行相应的转化解析。
一个简单的 JSON 数组:
- [
- "Qt",
- 5.7,
- true
- ]
生成比较简单,由于是一个数组,只需要用 QJsonArray 即可:
- // 构建 JSON 数组
- QJsonArray json;
- json.append("Qt");
- json.append(5.7);
- json.append(true);
-
- // 构建 JSON 文档
- QJsonDocument document;
- document.setArray(json);
- QByteArray byteArray = document.toJson(QJsonDocument::Compact);
- QString strJson(byteArray);
-
- qDebug() << strJson;
需要注意的是,和上面不同的是,这里使用的是 QJsonDocument 的 setArray() 函数,因为是数组嘛!解析如下:
- QJsonParseError jsonError;
- QJsonDocument doucment = QJsonDocument::fromJson(byteArray, &jsonError); // 转化为 JSON 文档
- if (!doucment.isNull() && (jsonError.error == QJsonParseError::NoError)) { // 解析未发生错误
- if (doucment.isArray()) { // JSON 文档为数组
- QJsonArray array = doucment.array(); // 转化为数组
- int nSize = array.size(); // 获取数组大小
- for (int i = 0; i < nSize; ++i) { // 遍历数组
- QJsonValue value = array.at(i);
- if (value.type() == QJsonValue::String) {
- QString strName = value.toString();
- qDebug() << strName;
- }
- if (value.type() == QJsonValue::Double) {
- double dVersion = value.toDouble();
- qDebug() << dVersion;
- }
- if (value.type() == QJsonValue::Bool) {
- bool bCrossPlatform = value.toBool();
- qDebug() << bCrossPlatform;
- }
- }
- }
- }
和 JSON 对象类似,在遍历数组时,获取每个 value,首先需要判断 value 的类型(和 is***() 函数类似,这里根据 type() 函数返回的枚举值来判断),然后再进行相应的转换。
构造一个复杂的 JSON 对象:
- {
- "Company": "Digia",
- "From": 1991,
- "Name": "Qt",
- "Page": {
- "Developers": "https://www.qt.io/developers/",
- "Download": "https://www.qt.io/download/",
- "Home": "https://www.qt.io/"
- },
- "Version": [
- 4.8,
- 5.2,
- 5.7
- ]
- }
包含了一个拥有五个 “key/value” 的对象,values 中的两个(Company、Name)是字符串,一个(From)是数字,一个(Page)是对象,一个(Version)是数组。
要生成这样一个复杂的 JSON 文档,需要分别构造对象和数组,然后将它们拼接起来:
- // 构建 Json 数组 - Version
- QJsonArray versionArray;
- versionArray.append(4.8);
- versionArray.append(5.2);
- versionArray.append(5.7);
-
- // 构建 Json 对象 - Page
- QJsonObject pageObject;
- pageObject.insert("Home", "https://www.qt.io/");
- pageObject.insert("Download", "https://www.qt.io/download/");
- pageObject.insert("Developers", "https://www.qt.io/developers/");
-
- // 构建 Json 对象
- QJsonObject json;
- json.insert("Name", "Qt");
- json.insert("Company", "Digia");
- json.insert("From", 1991);
- json.insert("Version", QJsonValue(versionArray));
- json.insert("Page", QJsonValue(pageObject));
-
- // 构建 Json 文档
- QJsonDocument document;
- document.setObject(json);
- QByteArray byteArray = document.toJson(QJsonDocument::Compact);
- QString strJson(byteArray);
-
- qDebug() << strJson;
解析部分其实并没有看起来这么复杂,只要一步步搞明白对应的类型,然后进行相应转化即可。
- QJsonParseError jsonError;
- QJsonDocument doucment = QJsonDocument::fromJson(byteArray, &jsonError); // 转化为 JSON 文档
- if (!doucment.isNull() && (jsonError.error == QJsonParseError::NoError)) { // 解析未发生错误
- if (doucment.isObject()) { // JSON 文档为对象
- QJsonObject object = doucment.object(); // 转化为对象
- if (object.contains("Name")) {
- QJsonValue value = object.value("Name");
- if (value.isString()) {
- QString strName = value.toString();
- qDebug() << "Name : " << strName;
- }
- }
- if (object.contains("Company")) {
- QJsonValue value = object.value("Company");
- if (value.isString()) {
- QString strCompany = value.toString();
- qDebug() << "Company : " << strCompany;
- }
- }
- if (object.contains("From")) {
- QJsonValue value = object.value("From");
- if (value.isDouble()) {
- int nFrom = value.toVariant().toInt();
- qDebug() << "From : " << nFrom;
- }
- }
- if (object.contains("Version")) {
- QJsonValue value = object.value("Version");
- if (value.isArray()) { // Version 的 value 是数组
- QJsonArray array = value.toArray();
- int nSize = array.size();
- for (int i = 0; i < nSize; ++i) {
- QJsonValue value = array.at(i);
- if (value.isDouble()) {
- double dVersion = value.toDouble();
- qDebug() << "Version : " << dVersion;
- }
- }
- }
- }
- if (object.contains("Page")) {
- QJsonValue value = object.value("Page");
- if (value.isObject()) { // Page 的 value 是对象
- QJsonObject obj = value.toObject();
- if (obj.contains("Home")) {
- QJsonValue value = obj.value("Home");
- if (value.isString()) {
- QString strHome = value.toString();
- qDebug() << "Home : " << strHome;
- }
- }
- if (obj.contains("Download")) {
- QJsonValue value = obj.value("Download");
- if (value.isString()) {
- QString strDownload = value.toString();
- qDebug() << "Download : " << strDownload;
- }
- }
- if (obj.contains("Developers")) {
- QJsonValue value = obj.value("Developers");
- if (value.isString()) {
- QString strDevelopers = value.toString();
- qDebug() << "Developers : " << strDevelopers;
- }
- }
- }
- }
- }
- }
基本的用法就这些,比较简单,细节很关键,建议在处理的过程中启用严格模式,例如:先通过 QJsonParseError::NoError 判断转化 JSON 文档无误,再进行解析。在解析过程中,先判断 QJsonValue 是否为对应的类型如 isObject(),再通过 toObject() 转化。
JSON的解析要对照JSON字符串来理解,关于JSON字符串的介绍,可以参考JSON简介
首先,解析和构建都要包含如下头文件:
- #include <QJsonDocument>
- #include <QJsonObject>
- #include <QJsonArray>
这个 JSON 字符串中 HeWeather6 键的值是一个数组,数组内只有 1 个 JSON 对象,这个对象里又嵌套了几个 JSON 对象。
- {
- "HeWeather6": [{
- "basic": {
- "cid": "CN101010700",
- "parent_city": "北京",
- "cnty": "中国",
- },
- "status": "ok",
- }]
- }
主要是 JSON 的多层嵌套的解析。解析函数:
- int Parse_HeWeather_Now_Json(void)
- {
- QJsonParseError err_rpt;
- QJsonDocument root_Doc = QJsonDocument::fromJson(he_now_json, &err_rpt); // 字符串格式化为JSON
-
- if(err_rpt.error != QJsonParseError::NoError)
- {
- qDebug() << "JSON格式错误";
- return -1;
- }
- else // JSON格式正确
- {
- //qDebug() << "JSON格式正确:\n" << root_Doc;
-
- QJsonObject root_Obj = root_Doc.object();
- QJsonValue weather_Value = root_Obj.value("HeWeather6"); // HeWeather6键的值,是一个数组
- if(weather_Value.isArray()) // 可省略
- {
- QJsonObject weather_Obj = weather_Value.toArray().at(0).toObject(); // HeWeather6数组就含有一个元素0
-
- /* basic键信息 */
- QJsonObject basic_Obj = weather_Obj.value("basic").toObject();
- QString cid = basic_Obj.value("cid").toString();
- QString parent_city = basic_Obj.value("parent_city").toString();
- QString cnty = basic_Obj.value("cnty").toString();
- QString basic_info = cid + " " + parent_city + " " + cnty;
- qDebug() << basic_info;
-
- QString status = "解析状态:" + weather_Obj.value("status").toString(); //"ok"
- qDebug() << status;
- }
- return 0;
- }
这个字符串和上面那个一样,都是数组元素是 JSON 对象,对象的值又是一个 JSON 对象。
- {
- "results": [{
- "location": {
- "id": "WX4FBXXFKE4F",
- "name": "北京",
- "country": "CN",
- "path": "北京,北京,中国",
- "timezone": "Asia/Shanghai",
- "timezone_offset": "+08:00"
- },
- "now": {
- "text": "晴",
- "code": "1",
- "temperature": "-7"
- },
- "last_update": "2018-12-06T22:05:00+08:00"
- }]
- }
解析函数:
- int Parse_Seniverse_Now_Json(void)
- {
- QJsonParseError err_rpt;
- QJsonDocument root_Doc = QJsonDocument::fromJson(seniverse_now_json, &err_rpt); // 字符串格式化为JSON
- if(err_rpt.error != QJsonParseError::NoError)
- {
- qDebug() << "JSON格式错误";
- return -1;
- }
- else // JSON格式正确
- {
- //qDebug() << "JSON格式正确:\n" << root_Doc;
- QJsonObject root_Obj = root_Doc.object();
- QJsonValue result_Value = root_Obj.value("results");
- if(result_Value.isArray())
- {
- QJsonObject result_Obj = result_Value.toArray().at(0).toObject();
-
- QString last_update = result_Obj.value("last_update").toString();
- qDebug() << last_update;
-
- /* location键的值 */
- QJsonObject location_Obj = result_Obj.value("location").toObject();
- QString id = location_Obj.value("id").toString();
- QString name = location_Obj.value("name").toString();
- QString timezone = location_Obj.value("timezone").toString();
- QString path = location_Obj.value("path").toString();
- QString loc_str = id + " " + name + " " + timezone + " " + path ;
- qDebug() << loc_str;
-
- /* now键 */
- QJsonObject now_Obj = result_Obj.value("now").toObject();
- QString code = "天气代码: " + now_Obj.value("code").toString();
- QString temperature = "当前温度:" + now_Obj.value("temperature").toString();
- QString text = "天气:" + now_Obj.value("text").toString();
- qDebug() << code << temperature << text;
- }
- }
- return 0;
- }
JSON字符串为:
- {
- "data": {
- "list":[
- {"id":"20200602221529"},
- {"id":"20200602203158"},
- {"id":"20200602175752"}
- ],
- "pagecnt":5,
- "pageindex":2
- },
- "result":0,
- "type":25
- }
解析函数:
- QJsonParseError parseJsonErr;
- // 转化为JSON文档
- QJsonDocument jsonDoc = QJsonDocument::fromJson(response.toUtf8(), &parseJsonErr);
- // 解析未发生错误
- if(parseJsonErr.error == QJsonParseError::NoError)
- {
- QJsonObject rootObj = jsonDoc.object(); // 转化为root对象
-
- QJsonValue rootValue = rootObj.value("data"); // 获取指定key对应的value,
- QJsonObject arrObject = rootValue.toObject(); // 再将值转换为obj:上一级key对应的值实际为数组对象
-
- QJsonValue arrValue = arrObject.value("list");
- if(arrValue.isArray()) // 判断获取的QJsonValue对象是不是数组结构
- {
- QJsonArray array = arrValue.toArray();
- for(int i=0;i<array.size();i++)
- {
- QJsonValue idValue = array.at(i);
- QJsonObject idObject = idValue.toObject();
- QString id = idObject["id"].toString();
- qDebug() <<"id=" <<id;
- }
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。