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

[simdjson] ondemand::value | object array

第四章:值类型

欢迎回来!

在前几章中,我们了解到解析器是处理JSON的工具,我们使用必要的填充字符串格式准备数据,调用parser.iterate()会返回一个文档对象,这是我们在按需API中处理JSON数据的起点

JSON文档结构由不同元素组成:对象{}、数组[]、字符串"类似这样"、数字1231.2、布尔值true/false以及null

当从根文档导航进入文档,或在数组/对象内部移动时,我们需要一种表示这些可能JSON元素的方法。

这就是simdjson::ondemand::value概念的由来。

什么是值类型?

在simdjson按需API中,simdjson::ondemand::value是一个临时句柄,表示在导航过程中发现的特定JSON元素。

它类似于指针或光标,当前高亮显示JSON数据中的某个项目。

关键点在于,value对象并不拥有其表示数据的任何内存。

它只是一个轻量级视图或句柄,指向:

  1. 原始填充的JSON缓冲区
  2. 解析器的内部状态(如结构索引或"磁带")

可用以下示意图表示:

在这里插入图片描述

value对象是我们在按需处理JSON数据时的主要交互方式。

我们通过其方法来判断JSON元素类型(例如是字符串?对象?数字?),并提取实际内容(获取字符串字符、数字值,或获取导航对象/数组的句柄)。

获取值类型

在遍历JSON结构时,可以通过以下方式获取simdjson::ondemand::value对象:

1. 从数组获取

遍历数组时,循环中的每个元素都是value

    #include <simdjson.h>int main() {simdjson::ondemand::parser parser;simdjson::padded_string json_data = R"([10, "hello", true, null])"_padded;auto doc = parser.iterate(json_data); // doc是文档对象// 假设doc是数组,获取数组句柄auto array = doc.get_array();// 遍历数组:每个'element'都是simdjson::ondemand::valuefor (auto element_result : array) {if (element_result.error()) { /* 处理错误 */ break; }simdjson::ondemand::value element = element_result.value();// 'element'现在代表数组中的元素(10、"hello"、true或null)// ... 使用'element' ...}return 0;}

2. 从对象获取

访问对象字段时,获取的结果是value类型:

#include <simdjson.h>int main() 
{simdjson::ondemand::parser parser;auto json_data = R"({"name": "simdjson", "version": 3})"_padded;auto doc = parser.iterate(json_data);auto object = doc.get_object();auto name_value = object["name"];  // 获取字符串值auto version_value = object["version"];  // 获取数字值return 0;
}

3. 从文档根获取(标量类型)

当根元素是简单标量时,可直接从文档获取value

#include <simdjson.h>int main() 
{simdjson::ondemand::parser parser;auto json_data = R"("字符串根元素")"_padded;auto doc = parser.iterate(json_data);simdjson::ondemand::value root_value = doc;  // 直接赋值return 0;
}

使用值类型:类型判断与内容提取

获取value后主要进行两个操作:

类型判断

通过type()方法判断元素类型:

auto type_result = element.type();
if (type_result.error()) break;
auto element_type = type_result.value();switch(element_type) {case json_type::number:   // 处理数字case json_type::string:    // 处理字符串case json_type::boolean:   // 处理布尔值// 其他类型处理...
}

内容提取

根据类型调用对应方法提取数据:

switch(element_type) {case json_type::number: {int64_t num = element.get_int64();  // 提取整型break;}case json_type::string: {std::string_view str = element.get_string();  // 提取字符串视图break;}// 其他类型提取方法...
}

生命周期与临时性

value对象具有临时性特征:

  1. 调用get_...()方法后,该值即被消费,原value失效
  2. 父容器迭代或超出作用域时,相关value也会失效

生命周期示意图:
在这里插入图片描述

最佳实践:

  • 获取value后立即提取数据
  • 长期存储应保存提取后的数据(如字符串、数字),而非value本身

底层原理

value本质上是value_iterator的包装器,包含指向原始JSON数据和解析器磁带状态的指针:

class value {value_iterator iter;  // 包含JSON指针和解析状态// 相关操作方法...
};

当调用type()时,迭代器仅检查当前标记类型;调用get_...()时会:

  1. 验证标记类型匹配
  2. 解析标记内容
  3. 推进迭代器位置

总结

  • value是表示单个JSON元素的临时句柄
  • 通过数组迭代、对象字段访问或文档根获取
  • 使用type()判断类型,get_...()提取内容
  • 具有临时性特征,需及时处理数据
  • 底层依赖解析器状态和原始数据缓冲区

下一章:对象与数组


第五章:object与array

在前几章中,我们掌握了解析器的核心作用,学习了如何用填充字符串准备JSON数据,以及如何通过parser.iterate()获取表示JSON根节点的文档对象(本质上是特殊的值类型)。

我们还了解到simdjson::ondemand::value是表示任意JSON元素的通用句柄。

JSON文档的结构化特性由JSON对象{})和JSON数组[])实现。当遇到表示对象或数组的值类型时,我们需要进入其内部结构进行访问。

这正是simdjson::ondemand::objectsimdjson::ondemand::array的设计目标。它们是用于导航JSON嵌套结构的专用句柄。

对象与数组句柄的定义

在simdjson按需API中:

  • simdjson::ondemand::object 是处理JSON对象({})的句柄,支持按键查找字段或遍历所有键值对
  • simdjson::ondemand::array 是处理JSON数组([])的句柄,支持遍历元素或按索引访问

与值类型类似,这些句柄不持有内存,它们是与原始填充字符串和解析器内部状态绑定的视图。

获取句柄

当值类型表示对象或数组时,可以获取对应句柄。若JSON根节点是对象或数组,可直接从文档获取初始句柄:

#include <simdjson.h>// 处理根对象
auto doc_obj = parser.iterate(R"({"message": "hello"})"_padded);
auto root_object = doc_obj.get_object();// 处理根数组
auto doc_array = parser.iterate(R"([1,2,3])"_padded);
auto root_array = doc_array.get_array();

对于嵌套结构的访问示例:

auto json = R"({"user": {"name": "Alice", "tags": ["simdjson", "cpp"]}})"_padded;
auto doc = parser.iterate(json);// 逐层获取句柄
auto root_obj = doc.get_object();
auto user_val = root_obj["user"];      // 获取用户对象值
auto user_obj = user_val.get_object(); // 转换为对象句柄
auto tags_val = user_obj["tags"];      // 获取标签数组值
auto tags_array = tags_val.get_array();// 转换为数组句柄

对象句柄操作

获取object句柄后,可通过两种方式访问字段:

按键访问

auto user_obj = doc.get_object();
auto name = user_obj["name"].get_string();    // 获取字符串
auto age = user_obj["age"].get_int64();       // 获取整型
auto is_student = user_obj["isStudent"].get_bool(); // 链式调用// 处理不存在字段
if (auto city = user_obj["city"]; city.error()) 
{std::cerr << "字段不存在: " << city.error();
}

遍历字段

for (auto field : user_obj) 
{auto key = field.key();      // 获取字段名auto value = field.value();  // 获取值句柄switch(value.type()) {case json_type::string: std::cout << key << ": " << value.get_string();break;// 其他类型处理...}
}

数组句柄操作

遍历元素

auto numbers = doc.get_array();
for (auto element : numbers) 
{if (element.type() == json_type::number) {std::cout << element.get_int64() << "\n";}
}

按索引访问

auto arr = doc.get_array();
auto second = arr.at(1).get_string();  // 访问索引1元素
auto tenth = arr.at(10);               // 越界访问将报错

生命周期管理

关键注意事项通过序列图展示:

在这里插入图片描述

实现原理

对象和数组句柄本质上是迭代器的包装

// 简化的对象句柄实现
class object 
{value_iterator iter;  // 内部迭代器value operator[](string_view key) {iter.find(key);    // 定位键值return value(iter.child());}
};// 简化的数组迭代器
class array_iterator 
{value_iterator iter;value operator*() {return value(iter);}void operator++() {iter.step();  // 推进迭代}
};

总结

  • 对象句柄支持按键查找和遍历字段
  • 数组句柄支持遍历和索引访问(注意O(N)复杂度)
  • 所有句柄均为临时视图,需及时处理数据
  • 操作会消耗迭代位置,禁止重复访问
  • 错误处理需检查每个simdjson_result

下一章:错误处理

http://www.xdnf.cn/news/1155961.html

相关文章:

  • 低速信号设计之I3C篇
  • 嵌入式Linux:获取线程ID
  • gym 安装
  • PrimeTime:高级片上变化(AOCV)
  • Laravel 框架NOAUTH Authentication required 错误解决方案-优雅草卓伊凡
  • 分享如何在保证画质的前提下缩小视频体积实用方案
  • NISP-PTE基础实操——XSS
  • MybatisPlus-14.扩展功能-DB静态工具-练习
  • windows + phpstorm 2024 + phpstudy 8 + php7.3 + thinkphp6 配置xdebug调试
  • MySQL学习----Explain
  • Kubernetes (K8S)知识详解
  • 二阶 IIR(biquad)滤波器
  • 红宝书单词学习笔记 list 51-75
  • Product Hunt 每日热榜 | 2025-07-20
  • 【c++】200*200 01灰度矩阵求所有的连通区域坐标集合
  • 去中心化协作智能生态系统
  • RK3588 安卓adb操作
  • Order Capital Round 1 (Codeforces Round 1038, Div. 1 + Div. 2) C、D
  • 讲解Mysql OnlineDDL的算法
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘lxml’问题
  • docker Neo4j
  • 【RK3576】【Android14】显示屏MIPI开发调试
  • 【图文详解】Transformer架构详细解析:多头自注意力机制、qkv计算过程、encoder架构、decoder架构以及mask的意义
  • Qwen3-8B 与 ChatGPT-4o Mini 的 TTFT 性能对比与底层原理详解
  • 网鼎杯2020青龙组notes复现
  • springboot websocket 自动重启方案
  • 彩虹云商城全源码 - 全新客服系统上线
  • CAN通讯理论与实践:调试和优化全讲解
  • 移动端开发的package命名规范
  • 《突破 GIL 限制:Python 多线程的真相与最佳实践》