本文主要介绍了使用Qt框架编程时如何解析JSON数据的一种方法。JSON是英文JavaScript Object Notation 的缩写,它是一种轻量级的数据交换格式,具有方便阅读和编写的优点,同时也易于机器解析和生成。JSON数据格式应用广泛,能够用于多种语言之间的数据交换。当前开源的C++JSON解析库有大概几十种,比较著名的有jsoncpp、nlohmann/json、rapidjson、jsonxx等。除此之外Qt5.0以上的版本也提供了JSON数据的读写支持。本文以jsoncpp库为例介绍如何使用第三方库实现JSON数据的读写。
按照国际惯例,这里使用Cmake来编译jsoncpp动态库。笔者是在Win10系统下编译的,首先打开cmake-gui,然后选择下载的jsoncpp源码路径,并设置好编译目录。如下图所示
依次点击 Configure、Generate、Open Project 按钮,打开生成的VS工程。
在解决方案上右键弹出菜单,选择【批生成】菜单项,在弹出的页面中勾选 “ALL_BUILD Debug"和"ALL_BUILD Release” ,如图所示
点击生成按钮,等待编译完成,查看是否生成对应的动态库文件。这种批生成其实也生成了对应debug和release版本的静态库。生成结束后打开build目录中的lib文件夹,可以看到Debug和Release两个目录。打开其中一个可以看到如下图所示内容
新建一个带界面的QT应用程序,把编译好的动态库引入到工程中。在pro文件中添加如下代码
INCLUDEPATH += $$PWD/include
CONFIG(debug) {
message(debug mode)
LIBS += -L$$PWD/lib -ljsoncppd
} else {
message(release mode)
LIBS += -L$$PWD/lib -ljsoncpp
}
DESTDIR = $$PWD/bin
其中include 目录中包含jsoncpp的头文件,lib目录下是jsoncpp动态库lib文件。并将对应的dll 文件拷贝到bin目录下。目录结构如下图所示
简单的创建一个界面来完成json数据的读写操作,UI如下图所示,左侧是一个用户信息表,右边是添加用户信息的页面。在输入框中输入用户信息,点击保存按钮新增用户信息,并把用户信息以JSON格式保存到文件中。点击刷新按钮,把文件中所有的用户信息读取到表格中。
保存按钮的槽函数为slot_saveUserInfo()。 writeDataToFile()函数将用户信息转为json数据格式,并写入到bin目录下的userList.json文件中。
void MainWindow::slot_saveUserInfo()
{
UserInfo userInfo;
userInfo.name = ui->le_name->text().trimmed();
userInfo.phone = ui->le_no->text().trimmed();
userInfo.address = ui->le_address->text().trimmed();
m_userList.append(userInfo);
writeDataToFile();
}
void MainWindow::writeDataToFile()
{
QString jsonFileName = qApp->applicationDirPath() + "/userList.json";
Json::Value userListVal;
for (int i = 0; i < m_userList.size(); i++)
{
Json::Value userInfo;
userInfo["name"] = m_userList[i].name.toLocal8Bit().data();
userInfo["phone"] = m_userList[i].phone.toLocal8Bit().data();
userInfo["address"] = m_userList[i].address.toLocal8Bit().data();
userListVal.append(userInfo);
}
Json::Value jsonRoot;
jsonRoot["userList"] = userListVal;
Json::StyledWriter writer;
std::string jsonData = writer.write(jsonRoot);
printf("jsonData:\n %s ", jsonData.c_str());
QFile jsonFile(jsonFileName);
if (jsonFile.open(QIODevice::WriteOnly))
{
qint64 nRet = jsonFile.write(jsonData.c_str());
if (nRet < 0)
{
qDebug() << "write data failed!";
}
jsonFile.close();
}
}
在页面上添加几条数据,查看userList.json文件内容,由于编码问题,中文是以Unicode编码的形式保存的。
{
"userList" : [
{
"address" : "\u5317\u4eac\u5e02\u6d77\u6dc0\u533a\u5f20\u5bb6\u6c9f\u6751",
"name" : "\u5f20\u4e09",
"phone" : "18078665544"
},
{
"address" : "\u5317\u4eac\u5e02\u6d77\u6dc0\u533a\u674e\u5bb6\u6c9f\u6751",
"name" : "\u674e\u56db",
"phone" : "18078665599"
}
]
}
点击刷新按钮,将文件中的数据,读取到页面的列表中。刷新按钮的响应函数是slot_refreshUserTable(),代码如下
void MainWindow::slot_refreshUserTable()
{
QString jsonFileName = qApp->applicationDirPath() + "/userList.json";
QFile jsonDataFile(jsonFileName);
if (jsonDataFile.open(QIODevice::ReadOnly))
{
std::string jsonStr = jsonDataFile.readAll().data();
Json::Value jsonRoot;
Json::Reader reader;
if (reader.parse(jsonStr, jsonRoot))
{
Json::Value userListVal = jsonRoot["userList"];
if (userListVal.isArray())
{
Json::Value::iterator iter = userListVal.begin();
m_userList.clear();
while (iter != userListVal.end())
{
Json::Value userInfo = userListVal[iter.index()];
UserInfo stUserInfo;
stUserInfo.name = userInfo.get("name", "").asCString();
stUserInfo.phone = userInfo.get("phone", "").asCString();
stUserInfo.address = userInfo.get("address", "").asCString();
m_userList.append(stUserInfo);
iter++;
}
updateTableWidget();
}
}
}
}
从上面的示例中,可以看到jsoncpp使用起来非常便捷,其核心类为Json::Value 、Json::StyledWriter、Json::Reader。其中Json为命名空间。
enum ValueType {
nullValue = 0, ///< 'null' value
intValue, ///< signed integer value
uintValue, ///< unsigned integer value
realValue, ///< double value
stringValue, ///< UTF-8 string value
booleanValue, ///< bool value
arrayValue, ///< array value (ordered list)
objectValue ///< object value (collection of name/value pairs).
};
Value的赋值
Json::Value userListVal; //arrayValue 类型
for (int i = 0; i < m_userList.size(); i++)
{
Json::Value userInfo; //objectValue 类型,直接通过下标赋值
userInfo["name"] = m_userList[i].name.toLocal8Bit().data();
userInfo["phone"] = m_userList[i].phone.toLocal8Bit().data();
userInfo["address"] = m_userList[i].address.toLocal8Bit().data();
userListVal.append(userInfo); //arrayValue 类型添加数据
}
Value类型判断,通过调用Value提供的一组API可以轻松的辨别数据的具体类型。
bool isNull() const;
bool isBool() const;
bool isInt() const;
bool isInt64() const;
bool isUInt() const;
bool isUInt64() const;
bool isIntegral() const;
bool isDouble() const;
bool isNumeric() const;
bool isString() const;
bool isArray() const;
bool isObject() const;
Value类型转换, 通过下面的API可以将Value转换成实际数据类型的数据。
String asString() const;
Int asInt() const;
UInt asUInt() const;
#if defined(JSON_HAS_INT64)
Int64 asInt64() const;
UInt64 asUInt64() const;
#endif // if defined(JSON_HAS_INT64)
LargestInt asLargestInt() const;
LargestUInt asLargestUInt() const;
float asFloat() const;
double asDouble() const;
bool asBool() const;
Json::StyledWriter writer;
std::string jsonData = writer.write(jsonRoot);
std::string jsonStr = jsonDataFile.readAll().data();
Json::Value jsonRoot;
Json::Reader reader;
if (reader.parse(jsonStr, jsonRoot))
{
//正确解析,DoSomthing
}
以上就是本文的所有内容,如有疑问欢迎您留言讨论。本文demo下载地址