zoukankan      html  css  js  c++  java
  • jsoncpp的简易教程

    Jsoncpp简易教程

    json简介

    json中仅支持两种结构:

    • 对象
    • 数组

    “名称/值”对的集合(A collection of name/value pairs)。一般称为对象(object)。不同的语言中,它被理解为对象(object),纪录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组 (associative array)。

    值的有序表,在大部分语言中,它被理解为数组(array)。

    你看到的json 要么{}包围,要么[]包围

    { 开头说明是个json对象
    [ 开头说明 这是个json数组

    pair

    一个pair(键值对)的通常结构是:
    string : value

    键值之间的对应关系使用 : 表示,左边的为key,右边的为value。
    一般key使用字符串,当然也可以使用数字,但是建议key只使用字符串
    value的取值就比较随便,可以是任何任何json支持的类型(比如object,array,string,number,true/false,null等)这就为嵌套类型带来了可能

    object

    object可以认为是多个pair的集合。
    其语法是以{作为object开始,以}作为object结束,不同的pair之间使用,分割。
    需要说明的是object中的数据存储是无序的。(所有你生成的json,在解析打印出来不一定是你生成的json顺序)

    {
    "name" : "tocy",
    "age" : 1000
    }
    

    array

    array是value的有序集合。
    其语法是以[作为array起始,以]作为array结束,array元素之间使用,分割。
    实际使用中建议在array中使用统一的类型,否则解析起来会麻烦点。

    // 合法
    [{"name":"tocy"}, {"age":1000}, {"domain":"cn"}]
    
    // 也合法,但是不方便解析
    [1, "ts", true, {"key":45}]
    

    jsoncpp的安装 --建议使用静态库

    1. Linux下比较简单。 jsoncpp项目里面有cmake配置文件。安装比较简单。
    2. Windows下比较麻烦点。推荐使用vcpkg安装或者使用VS的nuget安装。

    Linux下编译安装

    mkdir build && cd build && cmake ..
    make
    sudo make install
    // 如果没有生效
    // sudo ldconfig
    

    Windows下安装和集成到vs

    1. 使用vcpkg ./vcpkg.exe install jsoncpp:x64-windows-static 我使用的静态库
    2. 在VS中配置 头文件/库文件路径和链接器的输入文件 jsoncpp.lib
    3. 我这里使用的是静态库,如果使用的是动态库还需要在程序的运行目录放入jsoncpp.dll

    需要注意vcpkg的编译方式(MT/MTd MD/MDd) 静态库是MT/MTd,动态库是后者。

    如果vs报错4996,那是因为你使用了旧式的API,使用新式API或者关闭这个错误。

    在VS项目配置中 C/C++高级。禁用特定警告输入4996。 但是更加推荐使用新的API来解析和生成json。

    项目使用

    JsonCpp 中所有对象、类名都在 namespace Json 中, 只需要包含 json/json.h 即可。

    注意需要链接哦,我是用的cmake target_link_libraries(UseJsoncpp -ljsoncpp)

    jsoncpp核心介绍

    JsonCpp 主要包含三种类型的 class: (老式API讲解理论核心并不过时,这里按照老式的来讲,新式api只是为了安全而已)

    • Json::Value:可以表示所有支持的类型,如:int , double ,string , object, array等。其包含节点的类型判断(isNull,isBool,isInt,isArray,isMember,isValidIndex等),类型获取(type),类型转换(asInt,asString等),节点获取(get,[]),节点比较(重载<,<=,>,>=,==,!=),节点操作(compare,swap,removeMember,removeindex,append等)等函数。

    • Json::Reader:将文件流或字符串创解析到Json::Value中,主要使用parse函数。Json::Reader的构造函数还允许用户使用特性Features来自定义Json的严格等级。

    • Json::Writer:与JsonReader相反,将Json::Value转换成字符串流等,Writer类是一个纯虚类,并不能直接使用。在此我们使用 Json::Writer 的子类:Json::FastWriter(将数据写入一行,没有格式),Json::StyledWriter(按json格式化输出,易于阅读)

    jsoncpp解析json

    从文件中解析json

    真实场景就是当配置文件是json时候

    checkjson.json的内容为

    {
    "name" : "tocy",
    "age" : 1000
    }
    

    这里面保存的是最简单的object,我们可以使用下面代码将其读入并解析:

    void parse_from_file()
    {
    	std::ifstream ifs;
    	ifs.open("/home/tudou/tmp/checkjson.json"); // Windows自己注意路径吧
    	assert(ifs.is_open());
    	
    	Json::Reader reader;
    	Json::Value root;
        // 解析到root,root将包含Json里所有子元素
    	if (!reader.parse(ifs, root, false))
    	{
    		cerr << "parse failed 
    ";
    		return;
    	}
    	string name = root["name"].asString(); // 实际字段保存在这里, 因为知道是什么类型,所以直接用asString(),没有进行类型的判断
    	int age = root["age"].asInt(); // 这是整型,转化是指定类型
    	std::cout << name << ":" << age << "
    ";
    	ifs.close();
    }
    

    内存中解析json对象

    void parse_mem_object() {
    
        const char json_data[] =
                "{"name" : "Tocy", "salary" : 100, "msg" : "work hard", 
            "files" : ["1.ts", "2.txt"]}";
    #if 0
        // 推荐使用C++11的原始字符串
        const std::string rawString = R"({"name" : "tony", "salary" : 100, "msg" : "work hard", "file" : [ "1.ts", "2.txt" ]})";
    #endif
        Json::Reader reader;
        Json::Value root;
        // reader将Json字符串解析到root,root将包含Json里所有子元素,All!!!
        if (!reader.parse(json_data, json_data + sizeof(json_data), root)) {
            cerr << "json parse failed
    ";
            return;
        }
    
        cout << "demo read from memory ---------
    ";
        // 对象中key value
        string name = root["name"].asString();
        int salary = root["salary"].asInt();
        string msg = root["msg"].asString();
        cout << "name: " << name << " salary: " << salary;
        cout << " msg: " << msg << endl;
        cout << "enter files: 
    ";
        Json::Value files = root["files"]; // read array here
        // 注意这里Json::Value files 我们新定义了一个Json::Value类型的变量
        // 数组的解析写法还有其他的方式:
        // root[arraykey][index][subkey] 可以这样直接从根开始直接来操作
        for (unsigned int i = 0; i < files.size(); ++i) {
            // file[i] file[0] 数组中的第一个元素
            cout << files[i].asString() << " ";
        }
        cout << endl << endl;
    }
    // 我们可以看到数组的遍历
    // file[i] file[0] 数组中的第一个元素
    // 同理,如果json本身就是个数组,那么一开始就需要遍历
    // 看下面解析json数组的操作吧
    

    内存中解析json数组

    
    void parse_mem_array() {
    
    #if 0
    	const char json_data[] =
    		"[{"name" : "Tocy", "salary" : 100}, {"name" : "Kit", "salary" : 89}, 
            "a json note"]";
    
    #endif
    	// 这里我使用C++11带来的原始字符串
    	const std::string json_date = R"([{"name":"jack","salary":100}, {"name":"kit","salary":200}, "a json note"])";
    
    	Json::Reader reader;
    	Json::Value root;
    	// reader将Json字符串解析到root,root将包含Json里所有子元素
    	if (!reader.parse(json_date, root)) {
    		std::cerr << "parse fail! " << std::endl;
    		return;
    	}
    	
    	unsigned int count = root.size() - 1; // size() // Number of values in array or object
    	
    	// 最后一个比较特殊,所以i < count。 这也是为什么建议数组中的元素尽量是同一类型的原因
    	for (unsigned int i = 0; i < count; i++) {
    		// root[i]["name"] root[0]["name"] 第0个元素的name
    		std::string name = root[i]["name"].asString();
    		int salary = root[i]["salary"].asInt();
    		cout << "name: " << name << " salary: " << salary << endl;
    	}
    	// 最后一个元素单独处理
    	cout << "last msg: " << root[count].asString() << endl;
    }
    

    jsoncpp封装json

    json封装 简易的演示

    void demo_write_simple() {
    
    	Json::Value root; // root
    	Json::FastWriter writer;
    
    	Json::Value Person; // 子Value
    	Person["name"] = "tony";
    	Person["age"] = 22;
    	// 注意append方法的使用场景,只适用在添加数组item
    	root.append(Person);
    
    	string jsonStr = writer.write(root); // json到字符串
    
    	cout << "demo_write_simple ==============
    ";
    	cout << jsonStr << endl; 
    	// output: [{"age":22,"name":"tony"}]
    }
    

    json封装 内嵌array的object

    void demo_write_object() {
    	Json::Value root;
    	Json::FastWriter writer;
    
    	root["name"] = "tocy";
    	root["salary"] = 100;
    	root["msg"] = "work hard";
    
    	// 子value
    	Json::Value files;
    	files[0] = "1.ts";
    	files[1] = "2.txt";
    
    	root["files"] = files;
    	std::string json_data = writer.write(root);
    	cout << "demo write json object ==============
    ";
    	cout << json_data << endl;
    }
    // {"files":["1.ts","2.txt"],"msg":"work hard","name":"tocy","salary":100}
    

    json封装 内嵌object的array

    // tips: 构建一个json文件是json对象还是json数组。
    // 就看开始的根root,如果开始root[0] 明显是数组了
    void demo_write_array() {
    
    	Json::Value root;
    	Json::FastWriter writer;
    	// 对象1
    	// 使用{}只是为了隔离作用域
    	{
    		Json::Value person;
    		person["name"] = "jack";
    		person["salary"] = 200;
    		// index start 0
    		root[0] = person;
    	}
    
    	// 对象2
    	{
    		Json::Value person;
    		person["name"] = "miss";
    		person["salary"] = 1000;
    		//
    		root[1] = person;
    	}
    
    	root[2] = "a json note";
    
    	// to String Json::String等价于std::string
    	string json_data = writer.write(root);
    	cout << "demo write json ==============
    ";
    	cout << json_data << endl;
    }
    

    jsoncpp的新式API的使用

    封装json

    // 创建json字符串 新式API的使用
    std::string createJson()
    {
        std::string jsonStr;
        Json::Value root, language, mail;
        Json::StreamWriterBuilder writerBuilder; // 新式API
        std::ostringstream os;
    
        // 设置默认无格式化的输出
        writerBuilder.settings_["indentation"] = "";
    
        root["Name"] = "Zhangsan";
        root["Age"] = 25;
    
        language[0] = "C";
        language[1] = "C++";
        root["Language"] = language;
    
        mail["QQ"] = "zhangsan@qq.com";
        mail["Google"] = "san.zhang@gmail.com";
        root["E-mail"] = mail;
    
        root["Industry"] = "IT";
    
        // 这里使用智能指针
        std::unique_ptr<Json::StreamWriter> jsonWriter(writerBuilder.newStreamWriter());
        jsonWriter->write(root, &os); // json-->stringstream
        jsonStr = os.str(); // 转为string
    
        // 无格式化的输出
        std::cout << "Json-none:
    " << jsonStr << std::endl;
        // 格式化的输出
        std::cout << "Json-formatted:
    " << root.toStyledString() << std::endl;
    
        return jsonStr;
    }
    

    解析json

    bool parsrJSON()
    {
        const std::string rawString = R"({"name" : "tony", "salary" : 100, "msg" : "work hard"})";
    
        Json::Value root;
        Json::String errs;
        Json::CharReaderBuilder readBuilder; //
        std::unique_ptr<Json::CharReader> jsonRead(readBuilder.newCharReader());
        if (!jsonRead) {
            std::cerr << "jsonRead is null" << std::endl;
            return false;
        }
        // reader将Json字符串解析到root,root将包含Json里所有子元素
        bool ret = jsonRead->parse(rawString.c_str(), rawString.c_str() + rawString.length(), &root, &errs);
        if (!ret || !errs.empty()) {
            std::cout << "parseJsonFromString error!" << errs << std::endl;
            return false;
        }
        
        cout << "parsrJSON() read from memory using object start ! ---------
    ";
        // 看一下对象中key value
        string name = root["name"].asString();
        int salary = root["salary"].asInt();
        string msg = root["msg"].asString();
        cout << "name: " << name << " salary: " << salary;
        cout << " msg: " << msg << endl;
        cout << "parsrJSON() read from memory using object  end !---------
    ";
        return true;
    }
    

    给json添加字段(其实就是解析再封装)

    std::string parsrJSONAddItem(const std::string& rawString)
    {
    #if 0
        // 传递的rawString内容如下:
        const std::string rawString = R"({"name" : "tony", "salary" : 100, "msg" : "work hard"})";
    #endif
        // 先解析
        Json::Value root;
        Json::String errs;
        Json::CharReaderBuilder readBuilder;
        std::unique_ptr<Json::CharReader> jsonRead(readBuilder.newCharReader());
        if (!jsonRead) {
            std::cerr << "jsonRead is null" << std::endl;
            return std::string("");
        }
    
        // reader将Json字符串解析到root,root将包含Json里所有子元素
        bool ret = jsonRead->parse(rawString.c_str(), rawString.c_str() + rawString.length(), &root, &errs);
        if (!ret || !errs.empty()) {
            std::cout << "parseJsonFromString error!" << errs << std::endl;
            return std::string("");
        }
        cout << "demo read from memory using object ---------
    ";
    
        // 看一下对象中key value
        string name = root["name"].asString();
        int salary = root["salary"].asInt();
        string msg = root["msg"].asString();
        cout << "name: " << name << " salary: " << salary << " msg: " << msg << endl;
    
        // 添加两个字段
        root["from"] = "sdasdasd";
        root["to"] = "sadd22eewewe3";
    
        // 重新保存到字符串
        std::string jsonStr;
        Json::StreamWriterBuilder writerBuilder;
        std::ostringstream os;
     
        std::unique_ptr<Json::StreamWriter> jsonWriter(writerBuilder.newStreamWriter());
        jsonWriter->write(root, &os);
        jsonStr = os.str();
    
        std::cout << jsonStr << std::endl;
    
        return jsonStr;
    }
    

    jsoncpp其他常用的api

    • 判断json字符串中是否存在某键值的几种方法
    //  use isNull
    if (!root["key"].isNull()) //
    {
        std::string strValue= root["key"].asString(); // 已知key的value是string类型
        std::cout << strValue<< std::endl; 
    }
    // use isMember
    // jsoncpp判断Value中是否含有指定的key
    bool HasMember1(Json::Value& value, string key)
    {
        return value.isMember(key);
    }
    
    • 删除json中的对象
    root.removeMember("key"); // 可以直接使用value的removeMember方法删除指定的key
    
    • 类型判断 类型转换各种常用的api
    // 注:代码来自这位博主:https://www.cnblogs.com/dswcnblog/p/6678708.html
    // 写的非常的好
        if (reader.parse(str, value)) {
            //节点判断
            std::cout << "value's empty:" << value.empty() << std::endl;
            std::cout << "name is string:" << value["name"].isString() << std::endl;
            std::cout << "age is string:" << value["age"].isString() << std::endl;
    
            //类型获取
            std::cout << "name's type:" << value["name"].type() << std::endl;
            std::cout << "like's type:" << value["like"].type() << std::endl;
    
            //类型转换
            //根据Key获取值时最好判断类型,否则解析会中断
            std::cout << "name:" << value["name"].asString() << std::endl;
            std::cout << "age:" << value["age"].asInt() << std::endl;
    
            //节点获取
            std::cout << value["job"] << std::endl;                        //[]方式获取
            std::cout << value.get("name", "dxx") << std::endl;            //get方式获取
            std::cout << value.isMember("job") << std::endl;
            std::cout << "value's obj:" << value.isObject() << std::endl;
            std::cout << "like's obj:" << value["like"].isObject() << std::endl;
    
            std::cout << "like.size:" << value["like"].size() << std::endl;
            std::cout << "like[0][food]:" << value["like"][0]["food"].asString() << std::endl;
    
            //节点操作
            std::cout << "name compare age:" << value["name"].compare("age") << std::endl;
            value["name"] = "swduan";            //修改
            value["address"] = "hz";             //增加
            value["phone"] = "10086";        
            value.removeMember("age");           //删除
            value["like"][0]["sport"] = "game";  //往value["like"]中添加一项元素
    
            Json::Value item;
            item["hate"] = "game";
            value["like"].append(item);            //value["like"]中再添加一维数组
            std::cout << "value["like"]'s size:" << value["like"].size() << std::endl;
            
            std::cout << "--------------------" << std::endl;
            std::cout << value.toStyledString() << std::endl;
    
            std::cout << "--------------------" << std::endl;
            auto all_member = value.getMemberNames();
            for (auto member : all_member) {
                std::cout << member << std::endl;
            }
    
            std::cout << "--------------------" << std::endl;
            value.clear();        //清空元素
            std::cout << value.toStyledString() << std::endl;
        }
    
    

    注意事项

    • Value的size() 函数的返回值是返回值是 unsigned int; 可以点进去看下定义
      那么我们在for循环的时候就需要注意了!
        Json::Value files = root["files"]; // read array here
        // 需要注意的files.size() 的返回值是 unsigned int; 所以我们i 也需要定义为unsigned int 类型
        for (unsigned int i = 0; i < files.size(); ++i) {
            // file[i] file[0] 数组中的第一个元素
            cout << files[i].asString() << " ";
        }
    
    • 对不存在的键获取值会返回此类型的默认值
    • 通过key获取value时,要先判断value的类型,使用错误的类型获取value会导致程序中断。
    • 获取json数组中某一项key的value应该使用value[arraykey][index][subkey]获取或循环遍历数组获取。(所以我们也可以直接从root直接拿数组的信息)
    • append函数功能是将Json::Value添加到数组末尾。just for array!!!

    参考以及转载处


    欢迎交流学习,共同进步
    限本人水平有限,如有错误请指教,谢谢
  • 相关阅读:
    javascript延迟对象
    Fetch-新一代Ajax API
    AJAX笔记
    VR/AR/MR
    为什么Javascript有设计缺陷
    Javascript函数式编程
    vim基本操作
    Git 常用命令(二)
    SSH配置
    C# NPOI导出Excel和EPPlus导出Excel
  • 原文地址:https://www.cnblogs.com/__tudou__/p/14957646.html
Copyright © 2011-2022 走看看