【C++】JSON核心数据结构解析及JSONCPP使用

文章目录

json中的常见数据结构

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,基于JavaScript对象语法,但独立于编程语言,其核心是通过键值对组织数据,支持多种基础数据结构和复合结构。以下是JSON中最常见的数据结构,结合示例和特点详细说明:

一、基础数据类型(原子结构)

JSON的基础类型是构成复杂结构的最小单元,共6种核心类型:

类型 说明 示例
字符串 双引号包裹的Unicode字符,支持转义(\"/\\/\//\b/\f/\n/\r/\t/\uXXXX "name": "张三"
数字 整数、浮点数,支持负数、科学计数法(无八进制/十六进制) "age": 25, "price": 99.9, "count": 1e3
布尔值 true/false(小写,无引号) "isStudent": true
null 表示空值(小写,无引号) "address": null
对象 键值对的无序集合(复合类型,下文详细说明) {"id": 1, "name": "李四"}
数组 有序的值列表(复合类型,下文详细说明) ["苹果", "香蕉", 3.14]

注意:JSON中不支持 undefined、函数、日期(需转为字符串/数字)、正则表达式等JavaScript特有的类型。

二、核心复合结构

1. JSON对象(Object)
  • 定义 :以{}包裹的无序键值对集合,键必须是双引号包裹的字符串,值可以是任意JSON基础类型/复合类型。
  • 语法规则
    • 键值对之间用,分隔,最后一个键值对后不能加逗号(否则解析报错);
    • 键和值之间用:分隔;
    • 键必须是字符串(单引号/无引号均不合法)。
  • 示例
json 复制代码
{
  "id": 1001,
  "userInfo": {
    "username": "zhangsan",
    "email": "zhangsan@example.com"
  },
  "hobbies": ["篮球", "阅读"],
  "isVip": false,
  "score": null
}
  • 特点
    • 无序性:键值对的顺序不影响解析(不同解析器可能保留顺序,但标准不保证);
    • 嵌套性:值可以是另一个JSON对象(实现多层数据结构)。
2. JSON数组(Array)
  • 定义 :以[]包裹的有序值列表,值可以是任意JSON基础类型/复合类型(数组元素类型可不同)。
  • 语法规则
    • 元素之间用,分隔,最后一个元素后不能加逗号
    • 数组长度可通过索引获取(从0开始)。
  • 示例
json 复制代码
[
  101,
  "李四",
  {"age": 28, "city": "北京"},
  [1.80, 75.5],
  true,
  null
]
  • 典型场景:表示列表数据(如用户列表、商品列表):
json 复制代码
{
  "students": [
    {"id": 1, "name": "小明", "grade": 90},
    {"id": 2, "name": "小红", "grade": 95}
  ]
}
  • 特点
    • 有序性:元素顺序固定,可通过索引访问;
    • 异构性:数组内可混合不同类型的值(如数字、字符串、对象)。

三、常见组合结构(实际开发高频)

1. "对象+数组":列表型数据

最常用的结构,外层是对象(包含元信息),内层数组存放具体列表项:

json 复制代码
{
  "code": 200,          // 状态码
  "msg": "请求成功",     // 提示信息
  "data": {             // 数据体
    "total": 100,       // 总条数
    "list": [           // 列表数据
      {"id": 1, "name": "商品1", "price": 99},
      {"id": 2, "name": "商品2", "price": 199}
    ]
  }
}
2. "数组+对象":纯列表数据

直接返回数组,每个元素是对象(适用于简单列表):

json 复制代码
[
  {"date": "2026-01-01", "temperature": 10},
  {"date": "2026-01-02", "temperature": 12}
]
3. 嵌套对象:多层级数据

对象的值是另一个对象,实现数据的层级划分:

json 复制代码
{
  "user": {
    "basic": {
      "name": "王五",
      "age": 30
    },
    "contact": {
      "phone": "13800138000",
      "address": {
        "province": "广东",
        "city": "深圳"
      }
    }
  }
}
4. 数组嵌套数组:多维数据

适用于矩阵、坐标等场景:

json 复制代码
{
  "matrix": [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
  ],
  "points": [[10, 20], [30, 40], [50, 60]]
}

四、关键注意事项

  1. 语法严格性
    • 键必须用双引号({"name": "张三"} 合法,{name: "张三"}/{'name': '张三'} 不合法);
    • 末尾不能有多余逗号(如 [1,2,]/{"a":1,} 解析报错);
    • 数字不能以0开头(除0本身,如 0123 不合法);
  2. 空结构 :空对象{}、空数组[]是合法的,常用于默认值;
  3. 解析兼容性 :所有主流编程语言(Java/Python/Go/JavaScript等)都有JSON解析库,可将JSON字符串转为对应语言的对象/数组(如JavaScript的JSON.parse(),Python的json.loads())。

总结

JSON的核心是对象(无序键值对)数组(有序值列表) 两大复合结构,结合字符串、数字、布尔值、null四种基础类型,可灵活组合出各种复杂数据形态,是前后端交互、配置文件、数据存储的首选格式。实际开发中,最常用的是"对象包裹数组"的列表结构,需严格遵守JSON语法规则以避免解析错误。

jsoncpp数据结构

JsonCpp是C++中最常用的JSON解析/序列化库,其核心围绕Json::Value (表示任意JSON值)和辅助类(如Json::Reader/Json::Writer)构建,所有JSON数据结构最终都映射为Json::Value的不同类型。以下是JsonCpp中核心数据结构、用法及对应JSON结构的映射关系,结合示例详细说明:

一、核心基础类:Json::Value

Json::Value是JsonCpp的核心,可表示JSON支持的所有数据类型(字符串、数字、布尔、null、对象、数组),是一个"万能容器",通过类型区分和方法调用操作不同JSON结构。

1. Json::Value的类型枚举(对应JSON基础类型)

JsonCpp通过Json::ValueType枚举定义了Json::Value的类型,与JSON原生类型一一对应:

Json::ValueType枚举值 对应JSON类型 说明 示例初始化
nullValue null 空值 Json::Value val;(默认null)
intValue 整数 32位整数(超出用uintValue/realValue Json::Value val(100);
uintValue 无符号整数 无符号32位整数 Json::Value val((unsigned int)200);
realValue 浮点数 双精度浮点数 Json::Value val(3.1415);
stringValue 字符串 UTF-8字符串 Json::Value val("hello json");
booleanValue 布尔值 true/false Json::Value val(true);
arrayValue 数组 有序值列表 Json::Value val(Json::arrayValue);
objectValue 对象 无序键值对(键为字符串) Json::Value val(Json::objectValue);
2. Json::Value的核心操作方法
操作类型 方法示例 说明
类型判断 val.isNull()/val.isInt()/val.isArray() 判断当前Value的类型
取值(基础类型) val.asInt()/val.asString()/val.asBool() 转为对应C++类型(类型不匹配返回默认值)
数组操作 val.append(123)/val[0]/val.size() 追加元素、索引访问、获取数组长度
对象操作 val["name"] = "张三"/val.get("age", 0) 键值赋值、按键取值(无则返回默认值)
遍历(对象) Json::Value::Members keys = val.getMemberNames() 获取所有键名,遍历键值对
遍历(数组) for (int i=0; i<val.size(); i++) { val[i]; } 按索引遍历数组元素

二、JsonCpp核心数据结构(对应JSON复合结构)

1. JSON对象 → Json::Value(objectValue类型)
  • 映射关系 :JSON对象{"key": value}对应Json::ValueobjectValue类型,通过字符串键访问值。
  • 示例代码
cpp 复制代码
#include <json/json.h>
#include <iostream>

int main() {
    // 1. 构建JSON对象
    Json::Value user(Json::objectValue);
    user["id"] = 1001;                // intValue
    user["name"] = "张三";            // stringValue
    user["isVip"] = true;             // booleanValue
    user["score"] = Json::nullValue;  // nullValue
    user["price"] = 99.9;             // realValue

    // 2. 访问对象值
    std::cout << "ID: " << user["id"].asInt() << std::endl;
    std::cout << "Name: " << user["name"].asString() << std::endl;
    // 安全取值(键不存在时返回默认值0)
    std::cout << "Age: " << user.get("age", 0).asInt() << std::endl;

    // 3. 遍历对象所有键值对
    Json::Value::Members keys = user.getMemberNames();
    for (const auto& key : keys) {
        std::cout << key << ": " << user[key] << std::endl;
    }

    return 0;
}
  • 输出

    ID: 1001
    Name: 张三
    Age: 0
    id: 1001
    name: "张三"
    isVip: true
    score: null
    price: 99.9

2. JSON数组 → Json::Value(arrayValue类型)
  • 映射关系 :JSON数组[v1, v2, v3]对应Json::ValuearrayValue类型,通过索引访问元素(索引从0开始)。
  • 示例代码
cpp 复制代码
#include <json/json.h>
#include <iostream>

int main() {
    // 1. 构建JSON数组
    Json::Value hobbies(Json::arrayValue);
    hobbies.append("篮球");    // 追加字符串
    hobbies.append("阅读");    // 追加字符串
    hobbies.append(25);       // 追加整数
    hobbies.append(3.14);     // 追加浮点数

    // 2. 访问数组元素
    std::cout << "数组长度: " << hobbies.size() << std::endl;
    std::cout << "第一个元素: " << hobbies[0].asString() << std::endl;
    std::cout << "第四个元素: " << hobbies[3].asDouble() << std::endl;

    // 3. 遍历数组
    for (int i = 0; i < hobbies.size(); ++i) {
        std::cout << "索引" << i << ": " << hobbies[i] << std::endl;
    }

    return 0;
}
  • 输出

    数组长度: 4
    第一个元素: 篮球
    第四个元素: 3.14
    索引0: "篮球"
    索引1: "阅读"
    索引2: 25
    索引3: 3.14

3. 嵌套结构(对象嵌套对象/数组)

实际开发中最常用的组合,对应JSON的嵌套结构,核心是Json::Value的嵌套赋值。

  • 示例:对象嵌套对象+数组
cpp 复制代码
#include <json/json.h>
#include <iostream>
#include <string>

int main() {
    // 外层对象
    Json::Value root(Json::objectValue);
    root["code"] = 200;
    root["msg"] = "请求成功";

    // 内层数据对象
    Json::Value data(Json::objectValue);
    data["total"] = 2;

    // 内层数组(列表数据)
    Json::Value list(Json::arrayValue);
    
    // 数组元素1
    Json::Value item1(Json::objectValue);
    item1["id"] = 1;
    item1["name"] = "商品1";
    item1["price"] = 99.9;
    list.append(item1);

    // 数组元素2
    Json::Value item2(Json::objectValue);
    item2["id"] = 2;
    item2["name"] = "商品2";
    item2["price"] = 199.9;
    list.append(item2);

    // 组装嵌套结构
    data["list"] = list;
    root["data"] = data;

    // 序列化输出(美化格式)
    Json::StyledWriter writer;
    std::string jsonStr = writer.write(root);
    std::cout << jsonStr << std::endl;

    return 0;
}
  • 输出(格式化后的JSON)
json 复制代码
{
   "code" : 200,
   "msg" : "请求成功",
   "data" : {
      "total" : 2,
      "list" : [
         {
            "id" : 1,
            "name" : "商品1",
            "price" : 99.9
         },
         {
            "id" : 2,
            "name" : "商品2",
            "price" : 199.9
         }
      ]
   }
}

三、辅助核心类(解析/序列化)

JsonCpp的"数据结构"不仅包含Json::Value,还包括用于解析JSON字符串、序列化Json::Value的辅助类:

类名 作用 核心方法
Json::Reader 解析JSON字符串为Json::Value bool parse(const std::string& jsonStr, Json::Value& root)
Json::Writer 抽象类,序列化Json::Value为字符串 子类实现std::string write(const Json::Value& root)
Json::FastWriter 轻量级序列化(无格式化,单行字符串) 继承Writer,输出紧凑JSON
Json::StyledWriter 美化序列化(带缩进、换行) 继承Writer,输出易读的格式化JSON
Json::StyledStreamWriter 流式美化序列化(直接写入流) void write(std::ostream& os, const Json::Value& root)
示例:解析JSON字符串为Json::Value
cpp 复制代码
#include <json/json.h>
#include <iostream>
#include <string>

int main() {
    // JSON字符串
    std::string jsonStr = R"({
        "name": "李四",
        "age": 28,
        "hobbies": ["游泳", "跑步"],
        "isMarried": false
    })";

    // 解析器
    Json::Reader reader;
    Json::Value root;

    // 解析JSON字符串
    if (!reader.parse(jsonStr, root)) {
        std::cerr << "解析失败: " << reader.getFormattedErrorMessages() << std::endl;
        return 1;
    }

    // 访问解析后的数据
    std::cout << "姓名: " << root["name"].asString() << std::endl;
    std::cout << "年龄: " << root["age"].asInt() << std::endl;
    std::cout << "第一个爱好: " << root["hobbies"][0].asString() << std::endl;

    return 0;
}

四、关键注意事项

  1. 类型安全
    • 调用asInt()/asString()等方法时,需确保Json::Value的类型匹配(如nullValue调用asInt()会返回0,无报错但可能逻辑异常);
    • 建议先通过isInt()/isString()等判断类型,再取值。
  2. 空值处理
    • 默认构造的Json::ValuenullValue,可通过isNull()判断;
    • 访问不存在的键/索引时,会返回一个nullValueJson::Value(而非崩溃)。
  3. 编码问题
    • JsonCpp默认处理UTF-8编码,若JSON字符串是GBK/GB2312,需先转换为UTF-8再解析。
  4. 版本差异
    • JsonCpp 1.9.x+ 推荐使用Json::CharReader/Json::CharReaderBuilder替代Json::ReaderReader已标记为过时),示例:

      cpp 复制代码
      Json::CharReaderBuilder builder;
      std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
      std::string err;
      bool ok = reader->parse(jsonStr.c_str(), jsonStr.c_str()+jsonStr.size(), &root, &err);

总结

JsonCpp的核心数据结构是Json::Value,它通过不同类型(objectValue/arrayValue/intValue等)映射JSON的所有原生结构,配合Reader(解析)和Writer(序列化)类,实现JSON与C++数据的双向转换。实际开发中,最常用的是objectValue(JSON对象)和arrayValue(JSON数组)的嵌套组合,需重点掌握Json::Value的赋值、访问、遍历方法,以及解析/序列化的基本流程。

相关推荐
tobias.b21 小时前
408真题解析-2009-9-数据结构-小根堆-排序
数据结构·408考研·408真题·真题解析
报错小能手21 小时前
线程池学习(二)线程池详解
c++·线程池
w-w0w-w21 小时前
C++泛型编程
开发语言·c++·算法
-西门吹雪21 小时前
C++线程之内存模型
c++
梵尔纳多21 小时前
绘制一个三角形
c++·图形渲染·opengl
D_FW1 天前
数据结构第二章:线性表
数据结构·算法
tobias.b1 天前
408真题解析-2009-8-数据结构-B树-定义及性质
数据结构·b树·计算机考研·408考研·408真题
汉克老师1 天前
GESP2025年12月认证C++六级真题与解析(单选题8-15)
c++·算法·二叉树·动态规划·哈夫曼编码·gesp6级·gesp六级
hk11241 天前
【Architecture/Refactoring】2026年度企业级遗留系统重构与高并发架构基准索引 (Grandmaster Edition)
数据结构·微服务·系统架构·数据集·devops