今天再介绍一个用于C++操作JSON的库,以前也介绍过相关库,不过使用上稍微的复杂一点,如果常写JS的话,就知道js操作JSON相当的方便
其实C++也有一个操作JSON非常方便强大库
JSON for Modern C++
这个库的使用基本不比JS操作JSON复杂多少,最大的亮点就是不需要依赖,只有一个单文件,文件只有800多K,使用的时候直接加入到你的项目一起编译就行
注:以下代码在cygwin gcc 11.3中调试通过
从它的仓库下载到源码后,把single_include/nlohmann/json.hpp,放到你的项目里,在要用的文件里引入这个文件,然后用using 使用这个json类。
下面演示一个最简单的json操作过程
#include "json.hpp"
using json = nlohmann::json;
json object = {{"a", 1}, {"b", 2}};
cout<<"object:"<<object<<endl;
object["c"]=3;
cout<<"object.c:"<<object["c"]<<endl;
输出如下
object:{"a":1,"b":2}
object.c:4
这是一个最简单使用操作方式,第3行,是创建了一个json对象,里面有a,b两个属性,值分别是1,2。这个类似用js创建了对象
let object = {"a":1, "b":2};
第5行,是给这个对象创建一个c属性,它的值是3,这个操作方式js里一样了,如果不存在c属性的话,就给他创建一个,如果有的话,就把他的值更新成最新的
上面的代码只是用于演示如何使用,事实上,在实际开发中,大多数不可能出现自己定义json,然后给自己使用的场景,多数还是要解析外来的json或者在程序中生成json给外部使用
从字符串解析,使用parse函数。假设调用了一个远处的API返回了如下text变量定义的内容
string text = R"(
{
"Code":1,
"Message":2,
"Data": [{
"a":1,
"b":2,
"c":3
},{
"a":4,
"b":5,
"c":6
}]
}
)";
json strjson = json::parse(text);
std::cout << "Code:"<<strjson["Code"]<< ",Message:"<<strjson["Message"]<<endl ;
nlohmann::basic_json v = strjson["Data"];
for (nlohmann::basic_json i : v)
{
std::cout << "a:" << i["a"]<< ",b:"<<i["b"]<<",c:"<<i["c"]<<endl ;
}
第16行,是从一个从字符串创建json对象,第17行是读取Code,Message的内容,第18行是读取Data的内容,并把它赋值给v,因为Data是数组类型,所以,可以使用循环,读取数组内的每个元素的内容,每个元素类型都是basic_json类型,然后使用[]读取每个属性
输出内容如下
Code:1,Message:2
a:1,b:2,c:3
a:4,b:5,c:6
如果你在程序中创建个json类,想给其他程序使用的话,就可以输出字符串,这个很简单,使用to_string()方法
json j = {{"one", 1}, {"two", 2}};
string s = to_string(j);
cout<<s<<endl;
输出如下
{"one":1,"two":2}
在JS中,可以使用for in 或者Object.getOwnPropertyNames输出对象的key,value.在本库中也可以输出,举例如下
json object = {{"a", 1}, {"b", 2}};
for (auto it = object.begin(); it != object.end(); ++it)
{
cout << "key: " << it.key() << ", value:" << it.value() << endl;
}
输出如下
key: a, value:1
key: b, value:2
除了第一个例子里增加属性的方式
object["c"]=3;
还可增加更深层的属性,比如
json object = {{"a", 1}, {"b", 2}};
object["c"]["d"]["tt"] = {2,3};
cout<<"object:"<<object<<endl;
输出如下
object:{"a":1,"b":2,"c":{"d":{"tt":[2,3]}}}
应为库本身重写了很多操作符,还以使用符号’+'来搞,用加号重写上面的代码
json object = {{"a", 1}, {"b", 2}};
object+={"c",{{"d",{{"tt",{2,3}}}}}};
cout<<"object:"<<object<<endl;
输出如下,和上面效果一样
object:{"a":1,"b":2,"c":{"d":{"tt":[2,3]}}}
但是这里要注意一点
创建属性一定要在属性外面多套一层花括号,否则它就被解析成数组了,例如上栗,如果d,c外没有多一层花括号,c,d最终就被解析成数组了,代码如下
json object = {{"a", 1}, {"b", 2}};
object+={"c",{"d",{"tt",{2,3}}}};
cout<<"object:"<<object<<endl;
输出如下
object:{"a":1,"b":2,"c":["d",["tt",[2,3]]]}
这个常用的场景可能是解析外来的json时候报错,可以使用try,catch捕获错误,然后用parse_error输出错误
try
{
json::parse("{\"a\",}");
}
catch (json::parse_error& e)
{
std::cout << e.what() << endl;
}
本例将输出错误信息
[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing object separator - unexpected ','; expected ':'
比如,有些属性需要再加工以后使用,要增加一些属性,或者删除一些属性,在此库中,可以使用erase方法删除属性,例如,从object 中把fg属性删掉
json object = {{"a", 1}, {"b", {{"f",{3,4}},{"fg",{3,4}}}}};
object["b"].erase("fg");
cout<<object<<endl;
输出如下
{"a":1,"b":{"f":[3,4]}}
使用erase的时候,参数是属性名,前面要一直指向他的父属性
例如,有如下json
json object = {{"a", 1}, {"b", 2},{"c",{{"d",{{"tt",{2,3}}}}}}};
如果要删除tt属性
json object = {{"a", 1}, {"b", 2},{"c",{{"d",{{"tt",{2,3}}}}}}};
object["c"]["d"].erase("tt");
cout<<object<<endl;
输出如下
{"a":1,"b":2,"c":{"d":{}}}
is_array :是否为数组
is_boolean:是否为bool值
is_null:是否为空
is_number:是否为数字
is_object:是否为object
is_string:是否字符串
举例如下
json object = {{"a", 1}, {"b", "b"}};
cout<<object["a"].is_string()<<endl;
cout<<object["a"].is_number()<<endl;
cout<<object["b"].is_number()<<endl;
cout<<object["b"].is_string()<<endl;
输出如下
0
1
0
1
查找某个属性的值,可以使用find,举例如下,从object 中找到tt属性的值
json object = {{"a", 1}, {"b", 2},{"c",{{"d",{{"tt",{2,3}}}}}}};
cout<< *object["c"]["d"].find("tt") <<endl;
输出如下
[2,3]
使用的时候,要从被找的属性的父属性上查找,不能从根上找,那样找不到,如果上例改为
json object = {{"a", 1}, {"b", 2},{"c",{{"d",{{"tt",{2,3}}}}}}};
cout<< *object.find("tt") <<endl;
这样就报错了
使用size方法,可以统计出,父属性下有多少个子属性
json object = {{"a", 1}, {"b", 2},{"c",{{"d",{{"tt",{2,3}}}}}}};
cout<< object.size() <<endl;
cout<< object["c"]["d"].size() <<endl;
输出如下
3
1
以上就是关于JSON for Modern C++的基本介绍,其它的方法还有很多,本文只例举了几个可能常用的方法