C++ JSON 库 jsoncpp 新API的使用方法
既然看到了这篇文章你肯定知道Json是什么东西了,网上有很多解析Json的开源库,最近工作需要用到Json解析,研究发现jsoncpp使用很方便,网上也有很多使用方法介绍,目前为止能查到的基本都是比较老的API使用方法,编译器会提醒使用的某些API已经被弃用了,有的编译器还会直接报错,既然推荐用新的那就学一下新API的使用方法吧,记录一下。JSONCPP是C++中的生成与解析JSON 字符串的一种
既然看到了这篇文章你肯定知道Json是什么东西了,网上有很多解析Json的开源库,最近工作需要用到Json解析,研究发现jsoncpp使用很方便,网上也有很多使用方法介绍,目前为止能查到的基本都是比较老的API使用方法,编译器会提醒使用的某些API已经被弃用了,有的编译器还会直接报错,既然推荐用新的那就学一下新API的使用方法吧,记录一下。
JSONCPP是C++中的生成与解析JSON 字符串的一种实现。JSON是一种人比较容易理解,机器也比较容易解析的轻量级的数据交换格式。可以从Github上下载jsoncpp, https://github.com/open-source-parsers/jsoncpp。
使用方式
使用静态库/动态库
官方推荐使用Ninja进行编译,项目说明里有介绍。当然也可以使用比较常用的cmake进行编译
mkdir -p build/debug
cd build/debug
cmake -DCMAKE_BUILD_TYPE=debug -DBUILD_STATIC_LIBS=ON -DBUILD_SHARED_LIBS=ON -DARCHIVE_INSTALL_DIR=. -G "Unix Makefiles" ../..
make
生成的静/动态库文件目录为build/debug/src/lib_json/
,使用的时候把include头文件加到工程中,链接使用-ljsoncpp
参数指定链接库即可。
使用源文件
相比使用静态库,我更倾向于直接使用源文件,感觉这样比较方便。
在项目目录中直接执行python amalgamate.py
命令,会在dist
目录下生成两个头文件和一个源文件json-forwards.h
、json.h
和jsoncpp.cpp
。因为jsoncpp源码就四五千行,直接放在jsconcpp.cpp中和工程中其他代码一起编译也比较方便。
新API
这里随便写一个Json数据来演示,下面这个Json串包含了数组和内嵌Json串,一般常见的也就这样的吧。
{
"Name": "Liming",
"Age": 26,
"Language": ["C++", "Java"],
"E-mail": {
"Netease": "lmshao@163.com",
"Hotmail": "liming.shao@hotmail.com"
}
}
生成Json字符串
#include <iostream>
#include "json/json.h"
std::string createJson()
{
std::string jsonStr;
Json::Value root, lang, mail;
Json::StreamWriterBuilder writerBuilder;
std::ostringstream os;
root["Name"] = "Liming";
root["Age"] = 26;
lang[0] = "C++";
lang[1] = "Java";
root["Language"] = lang;
mail["Netease"] = "lmshao@163.com";
mail["Hotmail"] = "liming.shao@hotmail.com";
root["E-mail"] = mail;
std::unique_ptr<Json::StreamWriter> jsonWriter(writerBuilder.newStreamWriter());
jsonWriter->write(root, &os);
jsonStr = os.str();
std::cout << "Json:\n" << jsonStr << std::endl;
return jsonStr;
}
调用这个函数会输出
Json:
{
"Age" : 26,
"E-mail" :
{
"Hotmail" : "liming.shao@hotmail.com",
"Netease" : "lmshao@163.com"
},
"Language" :
[
"C++",
"Java"
],
"Name" : "Liming"
}
解析Json字符串
解析Json的前提是我们知道这个Json字符串里面包含了哪些数据,针对上面函数生成的Json串,我们使用下面这个函数来解析其中的数据。
bool parseJson(const std::string &info)
{
if (info.empty())
return false;
bool res;
JSONCPP_STRING errs;
Json::Value root, lang, mail;
Json::CharReaderBuilder readerBuilder;
std::unique_ptr<Json::CharReader> const jsonReader(readerBuilder.newCharReader());
res = jsonReader->parse(info.c_str(), info.c_str()+info.length(), &root, &errs);
if (!res || !errs.empty()) {
std::cout << "parseJson err. " << errs << std::endl;
}
std::cout << "Name: " << root["Name"].asString() << std::endl;
std::cout << "Age: " << root["Age"].asInt() << std::endl;
lang = root["Language"];
std::cout << "Language: ";
for (int i = 0; i < lang.size(); ++i) {
std::cout << lang[i] << " ";
}
std::cout << std::endl;
mail = root["E-mail"];
std::cout << "Netease: " << mail["Netease"].asString() << std::endl;
std::cout << "Hotmail: " << mail["Hotmail"].asString() << std::endl;
return true;
}
在main函数里面调用这个函数,以上一个函数的返回值作为输入参数会有如下输出:
Name: Liming
Age: 26
Language: "C++" "Java"
Netease: lmshao@163.com
Hotmail: liming.shao@hotmail.com
旧API
网上一搜多数都是旧API,懒得整理测试了,大概是这面这个样子。嵌套方式和上面新API操作一样。
生成Json
Json::Value root, ex;
Json::FastWriter writer;
root["Name"] = "Lucy";
root["age"] = 20;
ex[0] = "ABC";
ex[1] = "DEF";
root["exinfo"] = ex;
string json = writer.write(root);
解析Json
Json::Reader reader;
Json::Value root;
const char *jsonStr = "{\"Name\":\"Lucy\",\"Age\":20}";
if (!reader.parse(jsonStr, jsonStr + strlen(jsonStr), root)) {
std::cout << "json parse failed\n";
return 1;
}
std::string name = root["Name"].asString();
int age = root["Age"].asInt();
使用旧API编译器有诸如下面的提醒,有点编译器会报warning,有的编译器会报error,
warning: 'Reader' is deprecated: Use CharReader and CharReaderBuilder instead [-Wdeprecated-declarations]
warning: 'FastWriter' is deprecated: Use StreamWriterBuilder instead [-Wdeprecated-declarations]
坚持使用旧API可以在文件头部加入这段代码:
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#elif defined(_MSC_VER)
#pragma warning(disable : 4996)
#endif
总结
可以把Json::Value
理解为一个Json结构,这个类型可以嵌套,也可以当做数组一样使用,在需要的时候可以把这个结构转为相应的类型。
比如:
我们已经知道root["Name"]
存放的是一个string,可以把使用.asString()
转换为string
类型;
知道root["Language"]
这个Json::Value
是一个数组,就可以像数组一样使用下标进行取值;
知道root["E-mail"]
这个Json::Value
里面是嵌套的一个json,就可以和root
结构一样进行处理。Json::Value
其他的成员函数还有
// 转换类型
Int asInt() const;
UInt asUInt() const;
Int64 asInt64() const;
UInt64 asUInt64() const;
LargestInt asLargestInt() const;
LargestUInt asLargestUInt() const;
float asFloat() const;
double asDouble() const;
bool asBool() const;
// 检测类型
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;
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)