Qt之JSON生成与解析

简述

Qt5中包含了处理JSON的类,均以QJson开头(例如:QJsonDocument、QJsonArray、QJsonObject),在QtCore模块中,不需要额外引入其它模块。

常用的 JSON 库

json.org 中介绍了 JSON 在各种语言中的应用,在 C/C++ 中比较常用的JSON 库主要有以下几个:

  • JsonCpp
    JsonCpp 是一个 C++ 用来处理 JSON 数据的开发包。 网址:http://jsoncpp.sourceforge.net/
  • cJSON
    cJSON 是一个超轻巧,携带方便,单文件,简单的可以作为 ANSI-C 标准的 JSON 解析器。 网址:http://sourceforge.net/projects/cjson/
  • QJson
    QJson 是一个基于 Qt 的开发包用来将 JSON 数据解析成 QVariant 对象,JSON 的数组将被映射为QVariantList实例,而其他对象映射为 QVariantMap 实例。 网址:http://qjson.sourceforge.net/

关于 Qt 中对 JSON 的生成与解析,Qt5 以前的版本,可以使用 QJson 库,需要单独下载、编译,才能使用。到了 Qt5,提供了专门的 QJsonDocument 及其相关类来读和写 JSON 文档。

JSON 常用类

QJsonDocument

QJsonDocument 类用于读和写 JSON 文档。

一个 JSON 文档可以使用 QJsonDocument::fromJson() 从基于文本的表示转化为 QJsonDocument, toJson() 则可以反向转化为文本。解析器非常快且高效,并将 JSON 转换为 Qt 使用的二进制表示。

已解析文档的有效性,可以使用 !isNull() 进行查询。

如果要查询一个 JSON 文档是否包含一个数组或一个对象,使用 isArray() 和 isObject()。包含在文档中的数组或对象可以使用 array() 或 object() 检索,然后读取或操作。

也可以使用 fromBinaryData() 或 fromRawData() 从存储的二进制表示创建来 JSON 文档。

QJsonArray

QJsonArray 类封装了一个 JSON 数组。

JSON 数组是值的列表。列表可以被操作,通过从数组中插入和删除 QJsonValue 。

一个 QJsonArray 可以和一个 QVariantList 相互转换。可以使用 size() 来查询条目的数量,通过 insert() 在指定索引处插入值,removeAt() 来删除指定索引的值。

QJsonObject

QJsonObject 类封装了一个 JSON 对象。

一个 JSON 对象是一个“key/value 对”列表,key 是独一无二的字符串,value 由一个 QJsonValue 表示。

一个 QJsonObject 可以和一个 QVariantMap 相互转换。可以使用 size() 来查询“key/value 对”的数量,通过 insert() 插入“key/value 对”, remove() 删除指定的 key。

QJsonValue

QJsonValue 类封装了一个值。

JSON 中的值有 6 种基本数据类型:

  • bool(QJsonValue::Bool)
  • double(QJsonValue::Double)
  • string(QJsonValue::String)
  • array(QJsonValue::Array)
  • object(QJsonValue::Object)
  • null(QJsonValue::Null)

一个值可以由任何上述数据类型表示。此外,QJsonValue 有一个特殊的标记来表示未定义的值,可以使用 isUndefined() 查询。

值的类型可以通过 type() 或 isBool()、isString() 等访问函数查询。同样地,值可以通过 toBool()、toString() 等函数转化成相应的存储类型。

QJsonParseError

QJsonParseError 类用于在 JSON 解析中报告错误。
枚举 QJsonParseError::ParseError:该枚举描述 JSON 文档在解析过程中所发生的错误类型。

常量 描述
QJsonParseError::NoError 0 未发生错误
QJsonParseError::UnterminatedObject 1 对象不正确地终止以右花括号结束
QJsonParseError::MissingNameSeparator 2 分隔不同项的逗号丢失
QJsonParseError::UnterminatedArray 3 数组不正确地终止以右中括号结束
QJsonParseError::MissingValueSeparator 4 对象中分割 key/value 的冒号丢失
QJsonParseError::IllegalValue 5 值是非法的
QJsonParseError::TerminationByNumber 6 在解析数字时,输入流结束
QJsonParseError::IllegalNumber 7 数字格式不正确
QJsonParseError::IllegalEscapeSequence 8 在输入时,发生一个非法转义序列
QJsonParseError::IllegalUTF8String 9 在输入时,发生一个非法 UTF8 序列
QJsonParseError::UnterminatedString 10 字符串不是以引号结束
QJsonParseError::MissingObject 11 一个对象是预期的,但是不能被发现
QJsonParseError::DeepNesting 12 对解析器来说,JSON 文档嵌套太深
QJsonParseError::DocumentTooLarge 13 对解析器来说,JSON 文档太大
QJsonParseError::GarbageAtEnd 14 解析的文档在末尾处包含额外的乱码

简单的 JSON 对象

构造一个简单的 JSON 对象:

  1. {
  2. "Cross Platform": true,
  3. "From": 1991,
  4. "Name": "Qt"
  5. }

生成比较简单,由于是一个对象,只需要用 QJsonObject 即可。

  1. #include <QtWidgets/QApplication>
  2. #include <QtCore/QJsonObject>
  3. #include <QtCore/QJsonDocument>
  4. #include <qdebug.h>
  5. int main(int argc, char* argv[])
  6. {
  7. QApplication a(argc, argv);
  8. QJsonObject json;
  9. json.insert("name", "qt");
  10. json.insert("from", 1991);
  11. json.insert("cross platform", true);
  12. // 构建 JSON文档
  13. QJsonDocument document;
  14. document.setObject(json);
  15. QByteArray byteArray = document.toJson(QJsonDocument::Compact);
  16. QString strJson(byteArray);
  17. qDebug() << strJson << endl;
  18. return a.exec();
  19. }
  20. // "{\"cross platform\":true,\"from\":1991,\"name\":\"qt\"}"

解析如下:

  1. //#include "qjsonstudy.h"
  2. #include <QtWidgets/QApplication>
  3. #include <QtCore/QJsonObject>
  4. #include <QtCore/QJsonDocument>
  5. #include <qdebug.h>
  6. int main(int argc, char* argv[])
  7. {
  8. QApplication a(argc, argv);
  9. QByteArray byteArray = "{\"cross platform\":true,\"from\":1991,\"name\":\"qt\"}";
  10. QJsonParseError jsonError;
  11. QJsonDocument doucment = QJsonDocument::fromJson(byteArray, &jsonError); // 转化为 JSON 文档
  12. if (!doucment.isNull() && (jsonError.error == QJsonParseError::NoError)) { // 解析未发生错误
  13. if (doucment.isObject()) { // JSON 文档为对象
  14. QJsonObject object = doucment.object(); // 转化为对象
  15. if (object.contains("name")) { // 包含指定的 key
  16. QJsonValue value = object.value("name"); // 获取指定 key 对应的 value
  17. if (value.isString()) { // 判断 value 是否为字符串
  18. QString strName = value.toString(); // 将 value 转化为字符串
  19. qDebug() << "name : " << strName;
  20. }
  21. }
  22. if (object.contains("from")) {
  23. QJsonValue value = object.value("from");
  24. if (value.isDouble()) {
  25. int nFrom = value.toVariant().toInt();
  26. qDebug() << "from : " << nFrom;
  27. }
  28. }
  29. if (object.contains("cross platform")) {
  30. QJsonValue value = object.value("cross platform");
  31. if (value.isBool()) {
  32. bool bCrossPlatform = value.toBool();
  33. qDebug() << "cross platform : " << bCrossPlatform;
  34. }
  35. }
  36. }
  37. }
  38. qDebug() << byteArray << endl;
  39. return a.exec();
  40. }
  41. // name : "qt"
  42. // from : 1991
  43. // cross platform : true

注意:在转化为 QJsonDocument 后,首先需要根据 QJsonParseError 的值判定是否转化成功,然后在进行相应的转化解析。

简单的 JSON 数组

构造一个简单的 JSON 对象:

  1. [ "Qt", 5.7, true ]

生成比较简单,由于是一个数组,只需要用 QJsonArray 即可。

  1. //#include "qjsonstudy.h"
  2. #include <QtWidgets/QApplication>
  3. #include <QtCore/QJsonObject>
  4. #include <QtCore/QJsonDocument>
  5. #include <QtCore/QJsonArray>
  6. #include <qdebug.h>
  7. int main(int argc, char* argv[])
  8. {
  9. QApplication a(argc, argv);
  10. // 构建json数组
  11. QJsonArray json;
  12. json.append("Qt");
  13. json.append(5.7);
  14. json.append(true);
  15. // 构建json文档
  16. QJsonDocument document;
  17. document.setArray(json);
  18. QByteArray byteArray = document.toJson(QJsonDocument::Compact);
  19. QString strJson(byteArray);
  20. qDebug() << byteArray << endl;
  21. return a.exec();
  22. }
  23. // "[\"Qt\",5.7,true]"

需要注意的是,和上面不同的是,这里使用的是 QJsonDocument 的 setArray() 函数,因为是数组嘛!

  1. //#include "qjsonstudy.h"
  2. #include <QtWidgets/QApplication>
  3. #include <QtCore/QJsonObject>
  4. #include <QtCore/QJsonDocument>
  5. #include <QtCore/QJsonArray>
  6. #include <qdebug.h>
  7. int main(int argc, char* argv[])
  8. {
  9. QApplication a(argc, argv);
  10. QByteArray byteArray = "[\"Qt\",5.7,true]";
  11. QJsonParseError jsonError;
  12. QJsonDocument document = QJsonDocument::fromJson(byteArray, &jsonError);
  13. if(document.isArray()){
  14. if(!document.isNull() && (jsonError.error==QJsonParseError::NoError)) {
  15. if (!document.isEmpty()){
  16. QJsonArray array = document.array();
  17. int nSize = array.size();
  18. for(int i=0;i<nSize;i++){
  19. QJsonValue value = array.at(i);
  20. if (value.type() == QJsonValue::String) {
  21. QString strName = value.toString();
  22. qDebug() << strName;
  23. }
  24. if (value.type() == QJsonValue::Double) {
  25. double dVersion = value.toDouble();
  26. qDebug() << dVersion;
  27. }
  28. if (value.type() == QJsonValue::Bool) {
  29. bool bCrossPlatform = value.toBool();
  30. qDebug() << bCrossPlatform;
  31. }
  32. }
  33. }
  34. }
  35. }
  36. return a.exec();
  37. }
  38. // "Qt"
  39. // 5.7
  40. // true

和 JSON 对象类似,在遍历数组时,获取每个 value,首先需要判断 value 的类型(和 is*() 函数类似,这里根据 type() 函数返回的枚举值来判断),然后再进行相应的转换。

复杂的 JSON

构造一个复杂的 JSON 对象:

  1. {
  2. "Company": "Digia",
  3. "From": 1991,
  4. "Name": "Qt",
  5. "Page": {
  6. "Developers": "https://www.qt.io/developers/",
  7. "Download": "https://www.qt.io/download/",
  8. "Home": "https://www.qt.io/"
  9. },
  10. "Version": [ 4.8, 5.2, 5.7 ]
  11. }

包含了一个拥有五个“key/value 对”的对象,values 中的两个(Company、Name)是字符串,一个(From)是数字,一个(Page)是对象,一个(Version)是数组。
要生成这样一个复杂的 JSON 文档,需要分别构造对象和数组,然后将它们拼接起来:

  1. //#include "qjsonstudy.h"
  2. #include <QtWidgets/QApplication>
  3. #include <QtCore/QJsonObject>
  4. #include <QtCore/QJsonDocument>
  5. #include <QtCore/QJsonArray>
  6. #include <qdebug.h>
  7. int main(int argc, char* argv[])
  8. {
  9. QApplication a(argc, argv);
  10. // 构建Json数组 version
  11. QJsonArray versionArray;
  12. versionArray.append(4.8);
  13. versionArray.append(5.2);
  14. versionArray.append(5.7);
  15. // 构建Json对象 page
  16. QJsonObject pageObject;
  17. pageObject.insert("Home", "https://www.qt.io/");
  18. pageObject.insert("Download", "https://www.qt.io/download/");
  19. pageObject.insert("Developers", "https://www.qt.io/developers/");
  20. // 构建Json对象
  21. QJsonObject json;
  22. json.insert("Name", "Qt");
  23. json.insert("Company", "Digia");
  24. json.insert("From", 1991);
  25. json.insert("Version", QJsonValue(versionArray));
  26. json.insert("Page", QJsonValue(pageObject));
  27. // 构建json文档
  28. QJsonDocument document;
  29. document.setObject(json);
  30. QByteArray byteArray = document.toJson(QJsonDocument::Compact);
  31. QString strJson(byteArray);
  32. qDebug() << byteArray << endl;
  33. return a.exec();
  34. }
  35. // "{\"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]}"

解析部分其实并没有看起来这么复杂,只要一步步搞明白对应的类型,然后进行相应转化即可。

  1. //#include "qjsonstudy.h"
  2. #include <QtWidgets/QApplication>
  3. #include <QtCore/QJsonObject>
  4. #include <QtCore/QJsonDocument>
  5. #include <QtCore/QJsonArray>
  6. #include <qdebug.h>
  7. int main(int argc, char* argv[])
  8. {
  9. QApplication a(argc, argv);
  10. QJsonParseError jsonError;
  11. QByteArray byteArray = "{\"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]}";
  12. QJsonDocument doucment = QJsonDocument::fromJson(byteArray, &jsonError); // 转化为 JSON 文档
  13. if (!doucment.isNull() && (jsonError.error == QJsonParseError::NoError)) { // 解析未发生错误
  14. if (doucment.isObject()) { // JSON 文档为对象
  15. QJsonObject object = doucment.object(); // 转化为对象
  16. if (object.contains("Name")) {
  17. QJsonValue value = object.value("Name");
  18. if (value.isString()) {
  19. QString strName = value.toString();
  20. qDebug() << "Name : " << strName;
  21. }
  22. }
  23. if (object.contains("Company")) {
  24. QJsonValue value = object.value("Company");
  25. if (value.isString()) {
  26. QString strCompany = value.toString();
  27. qDebug() << "Company : " << strCompany;
  28. }
  29. }
  30. if (object.contains("From")) {
  31. QJsonValue value = object.value("From");
  32. if (value.isDouble()) {
  33. int nFrom = value.toVariant().toInt();
  34. qDebug() << "From : " << nFrom;
  35. }
  36. }
  37. if (object.contains("Version")) {
  38. QJsonValue value = object.value("Version");
  39. if (value.isArray()) { // Version 的 value 是数组
  40. QJsonArray array = value.toArray();
  41. int nSize = array.size();
  42. for (int i = 0; i < nSize; ++i) {
  43. QJsonValue value = array.at(i);
  44. if (value.isDouble()) {
  45. double dVersion = value.toDouble();
  46. qDebug() << "Version : " << dVersion;
  47. }
  48. }
  49. }
  50. }
  51. if (object.contains("Page")) {
  52. QJsonValue value = object.value("Page");
  53. if (value.isObject()) { // Page 的 value 是对象
  54. QJsonObject obj = value.toObject();
  55. if (obj.contains("Home")) {
  56. QJsonValue value = obj.value("Home");
  57. if (value.isString()) {
  58. QString strHome = value.toString();
  59. qDebug() << "Home : " << strHome;
  60. }
  61. }
  62. if (obj.contains("Download")) {
  63. QJsonValue value = obj.value("Download");
  64. if (value.isString()) {
  65. QString strDownload = value.toString();
  66. qDebug() << "Download : " << strDownload;
  67. }
  68. }
  69. if (obj.contains("Developers")) {
  70. QJsonValue value = obj.value("Developers");
  71. if (value.isString()) {
  72. QString strDevelopers = value.toString();
  73. qDebug() << "Developers : " << strDevelopers;
  74. }
  75. }
  76. }
  77. }
  78. }
  79. }
  80. return a.exec();
  81. }
  82. // Name : "Qt"
  83. // Company : "Digia"
  84. // From : 1991
  85. // Version : 4.8
  86. // Version : 5.2
  87. // Version : 5.7
  88. // Home : "https://www.qt.io/"
  89. // Download : "https://www.qt.io/download/"
  90. // Developers : "https://www.qt.io/developers/"

基本的用法就这些,比较简单,细节很关键,建议在处理的过程中启用严格模式,例如:先通过 QJsonParseError::NoError 判断转化 JSON 文档无误,再进行解析。在解析过程中,先判断 QJsonValue 是否为对应的类型如 isObject(),再通过 toObject() 转化。

链接:https://blog.csdn.net/foxgod/article/details/90407960