更正
通过数组的方式访问某个key也是会抛出异常的,只是它不能准确定位异常的位置,但是通过at方法是可以定位到具体异常的(如果访问的key不存在)。
引言
nlohman json GitHub - nlohmann/json: JSON for Modern C++ 是一个为现代C++(C++11)设计的JSON解析库,主要特点是
-
易于集成,仅需一个头文件,无需安装依赖
-
易于使用,可以和STL无缝对接,使用体验近似python中的json
常见用法
1. json初始化
1.1 从文件初始化
std::ifstream in_file("test.json");
nlohmann::json doc;
if (!in_file.is_open()) {
exit(1);
}
in_file >> doc;
in_file.close();
1.2 从字符串初始化
方式1
nlohmann::json doc = R"({"key1":"value1", "key2":[1,2,3]})"_json;
// nlohmann::json doc = "{\"key1\":\"value1\", \"key2\":[1,2,3]}"_json; // 此种情况下需要对json字符串中的双引号进行转义
-
R表示json字符串中的特殊字符均按照字符本身进行解析,而不需要进行转义,如双引号、反斜杠等字符
-
以 _json结尾表示其是一个json对象
方式2
std::string info = R"({"key1":"value1", "key2":[1,2,3]})";
nlohmann::json doc = nlohmann::json::parse(info);
- 调用json::parse方法,通过传入一个字符串进行构造,此时不以 _json结尾
1.3 直接构造json对象
方式1
// {"key1":"value1","key2":[1,2,3],"key3":{"key":"val"}}
nlohmann::json doc = {{"key1", "value1"}, {"key2", {1,2,3}}, {"key3", {{"key", "val"}}}};
-
最外层的花括号表示一个json object
-
里面的每一对花括号的第一个元素为key,第二个元素为value,用’,'分割
-
注意:单对花括号包裹的是array,两对花括号包裹的才是json object,如:
-
{1, 2}是一个array,即[1, 2]
-
{{1, 2}}是一个object,即{1:2},key为1,value为2
-
方式2
// {"app":"wechat","array":[1,2,4],"obj":{"age":15,"name":"zs","sex":"m"}}
nlohmann::json doc;
doc["app"] = "wechat"; // 添加一个k-v,若key存在则覆盖value
doc["array"] = {1,2,3}; // 添加一个数组
doc["array"].emplace_back(4); // 数组添加一个元素
doc["array"].erase(2); // 删除下标为2的元素
doc["obj"] = {{"name", "zs"}, {"age", 15}}; // 添加一个object
doc["obj"].push_back({"sex", "m"}); // 通过push方法添加一个k-v,若key存在则忽略,不会覆盖value
doc.push_back({"app", "qq"}); // key存在,故忽略
2. json访问
json展开如下:
{
"retCode": 0,
"retMSg": "成功",
"data": [
{
"name": "李雷",
"id": "001",
"score": {
"Chinese": 80,
"Math": 95
},
"schoolInfo": [
{
"School_name": "清华"
},
{
"School_name": "北大"
}
]
},
{
"name": "韩梅梅",
"id": "002",
"score": {
"Chinese": 90,
"Math": 80
},
"schoolInfo": [
{
"School_name": "清华"
},
{
"School_name": "北大"
}
]
}
]
}
循环遍历
std::string info = R"({"retCode":0,"retMSg":"成功","data":[{"name":"李雷","id":"001","score":{"Chinese":80,"Math":95},"schoolInfo":[{"School_name":"清华"},{"School_name":"北大"}]},{"name":"韩梅梅","id":"002","score":{"Chinese":90,"Math":80},"schoolInfo":[{"School_name":"清华"},{"School_name":"北大"}]}]})";
try {
nlohmann::json doc = nlohmann::json::parse(info);
} catch (std::expection& e){
// json转化失败会抛出异常,如json格式错误等
std::cout << e.what() << std::endl;
}
// 循环遍历
for (auto& item : doc.items()) {
const std::string& key = item.key();
auto& value = item.value(); // 用引用减少拷贝
if (value.is_number()) {
auto val = value.get<int>(); // 推导为int,如果是浮点型,转化为int则只保留整数部分
// int val = value; // 强转为int型
// auto val = value.get<uint32_t>();
// auto val = value.get<double>();
} else if (value.is_string()) {
const std::string& str = value;
// std::string str = value;
} else if (value.is_array()) { // value是一个数组
int len = value.size();
for (int i = 0; i < len; ++i) {
if (value[i].is_object()) {
;
} else if (value[i].is_string()) {
;
}
}
} else if (value.is_object()) { // value是一个json
for(auto& item_2 : value.items()) {
; // 类似处理
}
} else if (value.is_boolean()) {
bool b = value; // 或者直接用value进行传参,他会隐式转换为bool型
}
}
指定key遍历
std::string info = R"({"retCode":0,"retMSg":"成功","data":[{"name":"李雷","id":"001","score":{"Chinese":80,"Math":95},"schoolInfo":[{"School_name":"清华"},{"School_name":"北大"}]},{"name":"韩梅梅","id":"002","score":{"Chinese":90,"Math":80},"schoolInfo":[{"School_name":"清华"},{"School_name":"北大"}]}]})";
nlohmann::json doc = nlohmann::json::parse(info);
if (doc.contains("retCode") && doc["retCode"].is_number()) {
int retCode = doc["retCode"];
}
if (doc.contains("data") && doc["data"].is_array()) {
nlohmann::json& doc_arr = doc["data"];
int len = doc_arr.size();
} else if (doc.contains("data") && doc["data"].is_object()) {
nlohmann::json& doc_json = doc["data"];
}
访问key的几种方式
// 1. 直接通过key访问
std::string retMsg = doc["retMSg"]; // key不存在会出core(所以要判断key是否存在),类型转换失败也会core
// 2. 通过at方法访问
std::string retMsg = doc.at("retMSg"); // 同上,不同点在于at方法可以抛出异常(如果key不存在)
-
两种方式正常情况下返回的结果都是nlohmann::json对象,并且可以隐式转化为string以及各种基本类型
-
为了避免上述可能出现的问题,直接访问key对应的value时,尽量按如下方式编写程序:
-
先判断key是否存在(contains)
-
再判断key的类型,key类型相关的判断方法如下:
方法 含义 is_number 是否为数字(int、uint32_t、uint64_t、double等) is_boolean 是否为bool is_string 是否为字符串 is_array 是否为数组 is_object 是否为json -
-
当然也可以通过捕获异常的方式来达到避免程序出错的目的,注意由于doc[“retMSg”]这种访问方式不能抛出异常,应该使用doc.at(“retMSg”)这种方式来访问。
3. json序列化
json序列化就是将json对象序列化成json格式的字符串或者存储到文本文件
序列化为json字符串
string str = doc.dump();
保存为json文件
nlohmann::json doc;
doc["app"] = "wechat";
doc["age"] = 17;
std::ofstream out_file("test.json");
out_file << doc;