JSON文件
json在网络通信中经常被使用,特别是在与 pyhton、java服务交互时,常常要求传递、解析 json。
json文件格式
json标准符号
1.花括号 {}
2.双引号 ""
3.冒号 :
4.逗号 ,
5.中括号 []
json示例
{
"id" : 1,
"name" : "Tim",
"isFemal" : false,
"relevant" : null,
"children" : ["Jack","John","James"],
"address" : {
"street" : "Wiessenstrasse",
"postCode" : 100001
}
}
其中,id 为数值,name 为字符串,isFemal为布尔值,relevant为空,children为数组,address为对象。
json解析
这里使用QT中的 QJson模块来解析、构造 json。
// Json解析模块定义
struct JsonPrivate {
JsonPrivate(const QString &jsonOrJsonFilePath, bool fromFile);
void setValue(QJsonObject &parent, const QString &path, const QJsonValue &newValue);
QJsonValue getValue(const QString &path, const QJsonObject &fromNode) const;
QJsonObject root; // Json 的根节点
QJsonDocument doc; // Json 的文档对象
bool valid = true; // Json 是否有效
QString errorString; // Json 无效时的错误信息
};
// 在构造函数中读取、解析 json
JsonPrivate::JsonPrivate(const QString &jsonOrJsonFilePath, bool fromFile) {
QByteArray json("{}"); // json 的内容
// 如果传人的是 JsonUtil 文件的路径,则读取内容
if (fromFile) {
QFile file(jsonOrJsonFilePath);
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
json = file.readAll();
} else {
valid = false;
errorString = QString("Cannot open the file: %1").arg(jsonOrJsonFilePath);
qDebug() << errorString;
return;
}
} else {
json = jsonOrJsonFilePath.toUtf8();
}
// 解析 Json
QJsonParseError error;
doc = QJsonDocument::fromJson(json, &error);
if (QJsonParseError::NoError == error.error) {
root = doc.object();
} else {
valid = false;
errorString = QString("%1\nOffset: %2").arg(error.errorString()).arg(error.offset);
qDebug() << errorString;
}
}
属性值读取
// 读取属性的值,如果 fromNode 为空,则从跟节点开始访问
QJsonValue JsonPrivate::getValue(const QString &path, const QJsonObject &fromNode) const {
// 1. 确定搜索的根节点,如果 fromNode 为空则搜索的根节点为 root
// 2. 把 path 使用分隔符 . 分解成多个属性名字
// 3. 从搜索的根节点开始向下查找到倒数第二个属性名字对应的 QJsonObject parent
// 如 "user.address.street",要设置的属性为 street,它的 parent 是 address
// 4. 返回 parent 中属性名为倒数第一个属性名字对应的属性值
// [1] 确定搜索的根节点,如果 fromNode 为空则搜索的根节点为 root
// [2] 把 path 使用分隔符 . 分解成多个属性名字
QJsonObject parent = fromNode.isEmpty() ? root : fromNode;
QStringList names = path.split(QRegularExpression("\\."));
// [3] 从搜索的根节点开始向下查找到倒数第二个属性名字对应的 QJsonObject parent
int size = names.size();
for (int i = 0; i < size - 1; ++i) {
if (parent.isEmpty()) {
return QJsonValue();
}
parent = parent.value(names.at(i)).toObject();
}
// [4] 返回 parent 中属性名为倒数第一个属性名字对应的属性值
return parent.value(names.last());
}
属性值设置
void JsonPrivate::setValue(QJsonObject &parent, const QString &path, const QJsonValue &newValue) {
const int indexOfDot = path.indexOf('.'); // 第一个 . 的位置
const QString property = path.left(indexOfDot); // 第一个 . 之前的内容,如果 indexOfDot 是 -1 则返回整个字符串
const QString restPath = (indexOfDot > 0) ? path.mid(indexOfDot + 1) : QString(); // 第一个 . 后面的内容
QJsonValue fieldValue = parent[property];
if(restPath.isEmpty()) {
// 找到要设置的属性
fieldValue = newValue;
} else {
// 路径中间的属性,递归访问它的子属性
QJsonObject obj = fieldValue.toObject();
setValue(obj, restPath, newValue);
fieldValue = obj; // 因为 QJsonObject 操作的都是对象的副本,所以递归结束后需要保存起来再次设置回 parent
}
parent[property] = fieldValue; // 如果不存在则会创建
}
有了 JsonPrivate 模块,我们就可以很方便的读取、修改 json文件了。
对于示例中的json,我们可以这样去读取、修改:
读取
// jsonString为示例中的json
JsonPrivate jsonUtil(jsonString,false);
// 读取id
int idValue = jsonUtil.getValue("id").toInt();
// 读取name
QString nameValue = jsonUtil.getValue("name").toString();
// 读取isFemal
bool isFemalValue = jsonUtil.getValue("isFemal").toBool();
// 读取children
QStringList childrenList;
QJsonArray array = jsonUtil.getValue("children").toArray();
for (QJsonArray::const_iterator iter = array.begin(); iter != array.end(); ++iter) {
QJsonValue value = *iter;
childrenList << value.toString();
}
// 读取address
QString streetValue = jsonUtil.getValue("address.street").toString();
int postCodeValue = jsonUtil.getValue("address.postCode").toInt();
修改
// jsonString为示例中的json
JsonPrivate jsonUtil(jsonString, false);
// 修改id
jsonUtil.setValue(jsonUtil.root, "id", 2);
// 修改name
jsonUtil.setValue(jsonUtil.root, "name", "Lily");
// 修改isFemal
jsonUtil.setValue(jsonUtil.root, "isFemal", true);
// 修改children
QStringList childrenList = QStringList() << "Kevin" << "Peter";
QJsonArray array;
foreach(const QString &str, childrenList) {
array.append(str);
}
jsonUtil.setValue(jsonUtil.root, "children", array);
// 修改address
jsonUtil.setValue(jsonUtil.root, "address.street", "BaihuaRoad");
jsonUtil.setValue(jsonUtil.root, "address.postCode", 100002);