jsoncpp github地址: https://github.com/open-source-parsers/jsoncpp.git
下载源码后,可以通过多种方式进行 安装,例如cmake
mkdir build
cd build
cmake ..
make
make install #安装到系统
./build/lib文件夹中是静态库和动态库;当然可以同时将源码中的include文件夹拷贝到项目,可以使用这种源码依赖的方式,避免编译的时候不同版本之间有不兼容的情况。
可行的目录树为:
├── build
├── CMakeLists.txt
├── include
│ ├── json
│ │ ├── allocator.h
│ │ ├── assertions.h
│ │ ├── CMakeLists.txt
│ │ ├── config.h
│ │ ├── forwards.h
│ │ ├── json_features.h
│ │ ├── json.h
│ │ ├── PreventInBuildInstalls.cmake
│ │ ├── PreventInSourceBuilds.cmake
│ │ ├── reader.h
│ │ ├── value.h
│ │ ├── version.h
│ │ └── writer.h
│ ├── libjsoncpp.a
│ ├── libjsoncpp.so -> libjsoncpp.so.25
│ ├── libjsoncpp.so.1.9.5
│ └── libjsoncpp.so.25 -> libjsoncpp.so.1.9.5
└── json_test.cc
对应的CMakeLists.txt可以为:
cmake_minimum_required(VERSION 3.6)
set(app_name json_test)
project(${app_name})
include_directories(${CMAKE_SOURCE_DIR}/include)
link_directories(${CMAKE_SOURCE_DIR}/include)
add_executable(${app_name} json_test.cc)
target_link_libraries(${app_name} libjsoncpp.a)
json可以理解为三部分:
{
"env_name": "测试",
"node_name": "centos7",
"dns_time": 0.2,
"max_wait_time": 5,
"redirect": true,
"target_link": [
"1.0.0.0:1410",
"1.0.0.1:1411"
],
"redirect_details": {
"bj": "0.0.0.0",
"sh": "0.0.0.1"
},
"null_obj":{}
}
jsoncpp生成该对象:
Json::Value conf;
// 一般值
conf["env_name"] = "测试";
conf["node_name"] = "centos7";
conf["dns_time"] = 0.2;
conf["max_wait_time"] = 5;
conf["redirect"] = true;
// 数组
conf["target_link"] = Json::Value(Json::arrayValue);
conf["target_link"].append("1.0.0.0:1410");
conf["target_link"].append("1.0.0.1:1411");
// 对象
Json::Value redirect;
redirect["bj"] = "0.0.0.0";
redirect["sh"] = "0.0.0.1";
conf["redirect_details"] = redirect;
// 空对象
conf["null_obj"] = Json::Value(Json::objectValue);
return conf;
获取json对象后,希望获取各个值,有以下几种情况
已知结构或者部分结构的情况下可以按照key值进行获取,或者使用jsonpath进行抽取
未知结构的情况一般也没必要读取,需要的话当然也可以使用递归遍历
// 获取上述json对象
Json::Value conf = product();
// 一般值/对象
// 直接按照map的方式读取相当于 get default=NULL
std::clog << conf.get("env_name", "default_env").asString() << std::endl;
std::clog << conf["env_name"].asString() << std::endl;
std::clog << conf.get("env_name_", "default_env").asString() << std::endl;
std::clog << conf["env_name_"].asString() << std::endl;
// 数组
auto read_arr = [](const Json::Value& arr) {
if(!arr.isArray())return;
for(Json::ArrayIndex index=0; index < arr.size(); ++index){
std::clog << arr[index].asString() << std::endl;
// 一般情况下,在获取值之前都需要判断一下值的类型
// if(arr[index].isBool()){
// std::clog << arr[index].asBool() ? "true":"false";
// }
}
};
read_arr(conf["target_link"]);
// jsonpath 抽取
Json::Path path1(".redirect_details.sh");
std::clog << "jsonpath:" << path1.resolve(conf).asString() << std::endl;
Json::Path path2(".target_link[0]");
std::clog << "jsonpath:" << path2.resolve(conf).asString() << std::endl;
void lookup(const Json::Value& root, const char* key){
Json::ValueType type = root.type();
if(type <= Json::booleanValue){
std::clog <<"key=" << key <<",value=" << root.asString()<< std::endl;
}else if(type == Json::arrayValue){
for(Json::ArrayIndex index=0; index < root.size(); ++index){
lookup(root[index], key);
}
}else{
if(root.empty()){
std::clog <<"key=" << key <<",value= "<< std::endl;
return;
}
Json::Value::Members members = root.getMemberNames();
for(const auto& member : members){
lookup(root[member], member.c_str());
}
}
}
std::string write_str(const Json::Value &input, bool style= false){
if(!style){
Json::FastWriter writer;
return writer.write(input);
}
Json::StyledWriter writer;
return writer.write(input);
}
{"dns_time":0.20000000000000001,"env_name":"\u6d4b\u8bd5","max_wait_time":5,"node_name":"centos7","null_obj":{},"redirect":true,"redirect_details":{"bj":"0.0.0.0","sh":"0.0.0.1"},"target_link":["1.0.0.0:1410","1.0.0.1:1411"]}
{"dns_time":0.20000000000000001,"env_name":"测试","max_wait_time":5,"node_name":"centos7","null_obj":{},"redirect":true,"redirect_details":{"bj":"0.0.0.0","sh":"0.0.0.1"},"target_link":["1.0.0.0:1410","1.0.0.1:1411"]}
std::string write_str_factory(const Json::Value &input, bool style= false){
Json::StreamWriterBuilder writer_builder;
writer_builder["emitUTF8"] = true;
if(!style)
writer_builder["indentation"] = "";
std::unique_ptr<Json::StreamWriter> writer(writer_builder.newStreamWriter());
std::stringstream is;
if(writer->write(input, &is) != 0){
return "";
}
return is.str();
}
std::fstream output_file("./conf_bak.json", std::ios::out | std::ios::trunc);
output_file << write_str_factory(conf, true);
bool load_file(const char *file_path, std::string& content) {
std::fstream conf_file(file_path, std::ios::in | std::ios::binary);
if (!conf_file.is_open()) {
std::cerr << "open conf file failed, path:" << file_path << std::endl;
return false;
}
// 1. read file
Json::Reader reader;
Json::Value conf;
if(!reader.parse(conf_file, conf)){
std::cerr << "parse file content to json failed, path:" << file_path << std::endl;
return false;
}
// 2. to string
Json::FastWriter writer;
content = writer.write(conf);
std::clog << writer.write(conf) << std::endl;
return true;
}
同样也可以使用工厂
// 工厂1
Json::CharReaderBuilder read_builder;
std::unique_ptr<Json::CharReader> reader(read_builder.newCharReader());
if(!reader.parse(file_path, conf,false)){
return false;
}
// 工厂2
std::string errors;
if(!Json::parseFromStream(read_builder, conf_file, &conf, &errors)){
return false;
}
bool parse_str(const std::string& content, Json::Value& output){
// 1. Reader
Json::Reader reader;
if(!reader.parse(content, output)) return false;
// 2. CharReaderBuilder
Json::CharReaderBuilder read_builder;
std::unique_ptr<Json::CharReader> reader(read_builder.newCharReader());
if(!reader.parse(content, output, false)){
return false;
}
}
一般情况下,我们使用到的也就是生成一个json对象、读取对象的内容、序列化为字符串;从文件或者字符串中反序列化为对象读写。需要注意的有:
新版本中更推荐使用工厂类进行序列化与反序列化
对于中文序列化为utf8字符串时,在设置中调整一下 emitUTF8 这个选项为true
格式化读写,同样可以调整参数indentation=""
或是indentation=" "
jsonpath,使用Path类,语法中需要省去开头的$
符号,语法详情 JSONPath
现在很多场景下为了追求性能大多都在使用rapidjson, 但是不得不说jsoncpp还是比较易用的