C++ 使用nlohmann解析Json数据&数据对象建模

​ 援引百度百科:json是一种轻量级的数据交换格式。对于习惯了python语言的我来说,json可以和内置的dict(字典)数据类型完美衔接, 所以就想着能不能横向推广到C++。 在GitHub上一搜索,发现star最高的nlohmann;主要的用法工程的readme其实已经说的很清楚了。

​ 但是翻了很多博客,发现对于json 对象建模以及其相互转换的文档不多。此篇文章主要介绍读取json文件以及对象建模。希望对大家有所帮助!

一:将nlohmann库添加到自己的工程

​ 使用nlohmann,我们只需将json.hpp头文件添加到自己的代码中(这个超级Nice)

#include <json.hpp>

// 为了使用方便,可以让json命名空间内所有标识符在此文件中可见
using json = nlohmann::json;

二:简单json字符串序列化/反序列化

  1. 反序列化成json

    现有json字符串格式如下

    {
    	"pi":3.1415,
    	"happy":true
    }
    

    将其反序列化成json对象

    //方式1:在序列化后字符串后后添加 _json后缀
    json j = "{ \"happy\": true, \"pi\": 3.141 }"_json;
    
    //方式2:从原生字符串
    auto j2 = R"(
      {
        "happy": true,
        "pi": 3.141
      }
    )"_json;
    
    //方式3:显示的调用 json::parse
    auto j3 = json::parse(R"({"happy": true, "pi": 3.141})");
    
    //方式4:从json文件中读取
    std::ifstream ifs("test.json");
    json jf = json::parse(ifs);
    
  2. 序列化成json格式字符串

    // 显示的转换
    std::string s = j.dump();    // {"happy":true,"pi":3.141}
    
  3. 读取json文件

    std::ifstream ifs("test.json");
    json jf = json::parse(ifs);
    
  4. 保存成json文件

     jsonf jsonfile;
    
     jsonfile["happy"] = true;
     jsonfile["pi"] = 3.141;
     
     std::ofstream file("test.json");
     file << jsonfile;
    

三:较复杂的嵌套json字符串数据对象建模

现有json字符串格式如下:

{
	"teacher_name": "wangwu",
	"student_list": 
	[
		{
		"name": "zhangsan",
		"age": 16,
		"phone": "12345678"
		},
		{
		"name": "lisi",
		"age": 17,
		"phone": "123456"
		}
	]
}

对于较为复杂的嵌套json字符串,通用的做法是对其进行建模,对应到C++则是结构体/类

  1. json字符串分析

    直观的看的话, 此json字符串包含两种两大部分:teacher_name和student_list, 其中student_list是一个数组。student_list嵌套的内容包含name、age和phone3个字段

  2. 建模

    1. 最里层的表示学生对象的json字符串可转成对应的 student 类/结构体

      class student
      {
          public:	
              string name;
              int age;
              string phone;
      };
      
    2. 外层的表示班主任及学生列表的对象可转换成对应的***class_room***类/结构体, 其中学生列表可以用vector容器表示

      class class_room 
      {
          public:
              string teacher_name;
              std::vector<student> student_list;
      };
      
    3. 为了能够对这两个模型进行自由转换,需要对每个类/结构体分别提供两个函数

      // 对于student对象
      void from_json(const json& j, student& p)
      {
          j.at("name").get_to(p.name);
          j.at("age").get_to(p.age);
          j.at("phone").get_to(p.phone);
      }
      
      void to_json(json& j, const student& s)
      {
      	j = json{ { "name", s.name },{ "age",s.age },{ "phone", s.phone } };
      }
      
      
      //对于class_room对象
      void from_json(const json& j, class_room& p)
      {
          j.at("teacher_name").get_to(p.teacher_name);
      
          for (auto &student_t : j["student_list"])
          {
              student s;
              from_json(student_t, s);
              p.student_list.push_back(s);
          }
      }
      
      void to_json(json& j, const class_room& s)
      {
          j = json{ {"teacher_name", s.teacher_name } };
          for (auto & student_t : s.student_list)
          {
              json j_student;
              to_json(j_student, student_t);
              j["student_list"].push_back(j_student);
          }
      }
      

      当使用class_room字符串调用json的构造函数时,相应的to_json函数就会被调用,调用完成后对应的json对象就解析完成。反过来,如果调用***get***或者***get_to***时,from_json方法将会被调用

    4. 注意事项:

      1. 上面3步的都应包含在同一个namespace中,否则nlohmann库将不能正确的进行转换。代码结构示例如下
      namespace ns
      {
          class A
          {
          	// 一些结构体变量
          }
          void from_json(const json& j, A& a)
          {
          	// 转换的代码
          }
          void to_json(json& j, const A& a)
          {
          	// 转换的代码
          }
      }
      
      1. 需要用到这些转换的功能时,相应的头文件必须被包含,否则也不能转换成功
      2. 访问json的元素时,尽量使用 at() 方法而不要使用 ***operator[]***, 因为如果当有key不存在时,at() 方法会抛出异常而 operator[] 不会
  3. json字符串转换成数据对象

    ns::class_room cr;
    ns::from_json(commands, cr);
    
    //接下来就可以针对对象进行操作了
    std::cout << cr.student_list[0].age << std::endl;
    cr.student_list[0].age += 10;
    
  4. 数据对象转换

    json j_2;
    ns::class_room cr;
    ns::to_json(j_2, cr);
    

关注公众号【兰亭汇】即可获取完整代码~
公众号图片
感兴趣的同学可以看看。公众号会不定时分享工作生活中的所见所闻~


版权声明:本文为weixin_40603938原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。