当前位置: 首页 > news >正文

JsonCpp源码分析——Reader

1、与Writer模块功能相反,可以将Reader理解成一个反序列化的工具,Writer的作用主要是将Value对象转成string或者流式的结构,Reader的作用主要是将流式的结构转成Value类型的对象。Reader类的主要职责有3个,解析 JSON 字符串:将 JSON 格式的字符串读取并解析成相应的 C++ 数据结构。处理不同的数据类型,支持解析 JSON 对象、数组、字符串、数字、布尔值和 null。处理错误,在解析过程中,如果遇到格式错误或不符合 JSON 标准的情况,Reader 类能够捕获这些错误并提供相关的错误信息。示例代码如下:

#include <json/json.h>
#include <iostream>
#include <string>int main() {std::string jsonString = R"({"name": "Alice", "age": 30, "is_student": false})";Json::CharReaderBuilder readerBuilder;Json::Value root;std::istringstream jsonStream(jsonString);std::string errs;// 解析 JSON 字符串if (Json::parseFromStream(readerBuilder, jsonStream, &root, &errs)) {std::cout << "Name: " << root["name"].asString() << std::endl;std::cout << "Age: " << root["age"].asInt() << std::endl;std::cout << "Is Student: " << root["is_student"].asBool() << std::endl;} else {std::cerr << "Error parsing JSON: " << errs << std::endl;}return 0;
}

下面这个接口是实际开发中经常会用到的接口,当然我可以也可以向StreamWriterBuilder那样设置解析的属性,这个不难,不再进行介绍,后面会详细介绍下实现解析功能的精髓Token的设计。
bool JSON_API parseFromStream(CharReader::Factory const&, IStream&, Value* root,
String* errs);
2、Token是Reader模块中的精髓,它是jsoncpp 库中用于表示 JSON 数据流中各个组成部分的类。在 JSON 数据解析的过程中,Token 代表了 JSON 字符串中的基本元素,如对象的开始、数组的结束、字符串、数字等。通过对这些标记的处理,jsoncpp 能够逐步解析 JSON 数据并将其转换为 C++ 数据结构。Token的定义如下:

  enum TokenType {tokenEndOfStream = 0,     //数据流的结束tokenObjectBegin,         //对象的开始 {tokenObjectEnd,           //对象的结束 }tokenArrayBegin,          //数组的开始 [tokenArrayEnd,            //数组的结束 ]tokenString,              // stringtokenNumber,tokenTrue,tokenFalse,tokenNull,tokenArraySeparator,      //数组元素分隔符 ,tokenMemberSeparator,     // 对象成员分隔符 ,tokenComment,             // 注释tokenError                // 解析出错};class Token {public:TokenType type_;Location start_;Location end_;// start_ 表示标记的开始位置,end_ 表示标记的结束位置,识别出TokenType会根据这两个指针去解析对应的数据};

我觉着在解析Object时可以帮助理解Token的作用

bool Reader::readObject(Token& token) {Token tokenName;String name;Value init(objectValue);  // 创建一个对象类型的初始值currentValue().swapPayload(init);  // 将当前值设置为初始化的对象值currentValue().setOffsetStart(token.start_ - begin_);  // 设置对象的起始位置while (readToken(tokenName)) {  // 读取下一个标记bool initialTokenOk = true;// 跳过可能存在的注释while (tokenName.type_ == tokenComment && initialTokenOk)initialTokenOk = readToken(tokenName);if (!initialTokenOk)break;  // 如果读取注释失败,则退出循环// 如果遇到对象结束标记且没有名称,则表示对象为空if (tokenName.type_ == tokenObjectEnd && name.empty())return true;name.clear();  // 清除之前的名称// 处理对象的成员名称if (tokenName.type_ == tokenString) {if (!decodeString(tokenName, name))  // 解析字符串名称return recoverFromError(tokenObjectEnd);  // 解析错误,恢复错误处理} else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {Value numberName;if (!decodeNumber(tokenName, numberName))  // 解析数字名称return recoverFromError(tokenObjectEnd);  // 解析错误,恢复错误处理name = numberName.asString();  // 将数字转换为字符串作为名称} else {break;  // 如果名称不是字符串或数字,则退出循环}Token colon;// 读取冒号,检查是否存在冒号分隔符if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {return addErrorAndRecover("Missing ':' after object member name", colon, tokenObjectEnd);  // 如果缺少冒号,记录错误并恢复}Value& value = currentValue()[name];  // 获取当前值的对应成员nodes_.push(&value);  // 将成员值推入栈中bool ok = readValue();  // 读取成员的值nodes_.pop();  // 从栈中弹出成员值if (!ok)  // 如果读取值失败,错误已设置return recoverFromError(tokenObjectEnd);Token comma;// 读取逗号或对象结束标记,检查是否存在有效的分隔符if (!readToken(comma) ||(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&comma.type_ != tokenComment)) {return addErrorAndRecover("Missing ',' or '}' in object declaration", comma, tokenObjectEnd);  // 如果缺少逗号或结束标记,记录错误并恢复}bool finalizeTokenOk = true;// 跳过可能存在的注释while (comma.type_ == tokenComment && finalizeTokenOk)finalizeTokenOk = readToken(comma);if (comma.type_ == tokenObjectEnd)return true;  // 如果遇到对象结束标记,则成功解析对象并返回}return addErrorAndRecover("Missing '}' or object member name", tokenName, tokenObjectEnd);  // 如果缺少对象结束标记或成员名称,记录错误并恢复
}

http://www.mrgr.cn/news/24035.html

相关文章:

  • Java 访问修饰符详解:public、private、protected 及默认访问权限
  • 06_自平衡二叉搜索树
  • 【Petri网导论学习笔记】Petri网导论入门学习(二)
  • java基础-IO(6)转换流InputStreamReader、OutputStreamWriter
  • 元学习之应用案例
  • UML之类图详解
  • 《深入理解 JavaScript 中的定时器》
  • 一篇文章搞懂SQL优化
  • 学会这2项技能,普通人每年多赚10万+,互联网创业者必备!
  • Kerberos:更安全的网络认证协议
  • 香帅的金融学讲义:深入剖析与解读
  • Sklearn的datasets模块与自带数据集介绍
  • 使用 gdb 在汇编指令层面对程序注入、修改
  • 数据结构与算法1: 链表
  • Linux内核 -- 内存管理之 lru_cache_add_inactive_or_unevictable 函数
  • [Linux]:文件(下)
  • MySQL-CRUD入门2
  • 网络初识-相关概念
  • 《深度学习》OpenCV 高阶 图像直方图、掩码图像 参数解析及案例实现
  • 神经处理单元(NPU)小知识