十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Lynx 仓库内嵌的 RapidJSON:C++ 双 API JSON 解析/生成器完整指南

Lynx 仓库内嵌的 RapidJSON:C++ 双 API JSON 解析/生成器完整指南 Lynx 仓库内嵌的 RapidJSONC 双 API JSON 解析/生成器完整指南【免费下载链接】lynxEmpower the Web community and invite more to build across platforms.项目地址: https://gitcode.com/GitHub_Trending/lynx10/lynxRapidJSON 是腾讯开源的高性能 C JSON 解析/生成库同时提供 SAX 与 DOM 两套 API以header-only、零外部依赖、16 字节/值的极致设计著称。本文以 third_party/rapidjson/readme.md 为主线结合 Lynx 仓库中该库的实际集成构建配置、工具封装与业务调用带你掌握它的核心特性、安装构建方式、DOM/SAX 用法以及它在 Lynx 渲染引擎中的真实落地场景。一、RapidJSON 是什么RapidJSON 是一个 C 的 JSON 解析器及生成器其设计灵感来自 RapidXml。在 Lynx 仓库中它以third_party第三方依赖的形式完整内嵌头文件位于 third_party/rapidjson被 core 层的 JSON 工具、渲染与调试模块直接引用。RapidJSON 的核心定位可以浓缩为五句话特性说明小而全同时支持 SAX 和 DOM 两套 API其中 SAX 解析器仅约 500 行代码快性能可与strlen()相提并论可选 SSE2/SSE4.2 指令集加速自包含header-only不依赖 BOOST 等外部库甚至不依赖 STL内存友好在大多数 32/64 位机器上每个 JSON 值仅占 16 字节字符串除外默认使用快速内存分配器解析时紧凑分配内存Unicode 友好支持 UTF-8、UTF-16、UTF-32大端/小端及其检测、校验与转码支持代理对surrogate pair与\u0000空字符说明以上性能可比strlen()SAX 解析器约 500 行等表述均出自官方 readme 的项目自述属项目声明而非第三方测评结论。二、标准遵从与放宽语法JSONJavaScript Object Notation是一种轻量级数据交换格式。RapidJSON 宣称完全遵从RFC7159 / ECMA-404标准同时提供**可选的放宽语法relaxed syntax**支持包括注释comment尾随逗号trailing commaNaN/Infinity等非标准数值这意味着在默认严格模式下解析RapidJSON 行为与标准 JSON 完全一致在需要解析更宽松的配置、日志或调试数据时可开启放宽语法以兼容注释和尾随逗号。这在实际工程中非常实用——例如 Lynx 的调试环境序列化场景往往希望容忍人类手写的带注释 JSON。三、v1.1 版本亮点仓库内嵌的 RapidJSON 为 v1.1.0 版本readme 中徽章标注release-v1.1.0发布于 2016-8-25主要亮点如下新增 JSON Pointer可通过/a/b/c形式的指针路径便捷地访问与修改 DOM对应头文件 pointer.h新增 JSON Schema可在解析或生成 JSON 时按 Schema 进行校验对应头文件 schema.h新增放宽 JSON 语法如上节所述支持注释、尾随逗号、NaN/Infinity支持 C11 范围 for 循环遍历可直接用for (auto m : doc.GetObject())遍历 array 和 object内存优化在 x86-64 架构下每个Value的内存开销从 24 字节降至16 字节。四、在 Lynx 仓库中的集成方式Lynx 并没有对 RapidJSON 做任何源码修改而是通过 GN 构建系统将其声明为独立的 source_set供 core 层统一链接。4.1 构建配置C11 特性宏third_party/rapidjson/BUILD.gn 中的rapidjson_config是关键由于 RapidJSON 刻意不自动检测编译器能力Lynx 通过显式定义宏来启用其 C11 特性config(rapidjson_config) { include_dirs [ ., ../../third_party, ] # rapidjson needs these defines to support C11 features. These features # are intentionally not autodetected by rapidjson. defines [ RAPIDJSON_HAS_STDSTRING1, RAPIDJSON_HAS_CXX11_RANGE_FOR, RAPIDJSON_HAS_CXX11_RVALUE_REFS, RAPIDJSON_HAS_CXX11_TYPETRAITS, RAPIDJSON_HAS_CXX11_NOEXCEPT, ] ... }值得注意的细节RAPIDJSON_HAS_STDSTRING1开启std::string与GenericValue之间的无缝互操作RAPIDJSON_HAS_CXX11_RANGE_FOR对应 v1.1 的范围 for 遍历特性RAPIDJSON_HAS_CXX11_RVALUE_REFS/TYPETRAITS/NOEXCEPT让库充分利用 C11 移动语义与编译期优化这也是其性能与内存效率的基础。4.2 命名空间定制同一 BUILD.gn 中还支持通过 GN 变量rapidjson_namespace重命名 RapidJSON 的命名空间if (rapidjson_namespace ! ) { defines [ RAPIDJSON_NAMESPACE${rapidjson_namespace}::rapidjson, RAPIDJSON_NAMESPACE_BEGINnamespace ${rapidjson_namespace}{namespace rapidjson{, RAPIDJSON_NAMESPACE_END}};namespace rapidjson::${rapidjson_namespace}::rapidjson;, ] }这种设计可以避免多个第三方库同时内嵌 RapidJSON 时产生符号冲突——这是大型 C 项目中常见的现实问题。4.3 头文件清单third_party/rapidjson/rapidjson.gni 通过rapidjson_shared_sources列出了全部参与编译的头文件header-only 库无需 .cc 实现仅 internal/pow10.cc 一个实现文件并封装了rapidjson_source_set模板以便复用。完整清单包括DOM 层document.h、writer.h、prettywriter.hSAX 层reader.h、stream.h流封装stringbuffer.h、filereadstream.h、filewritestream.h、memorybuffer.h、memorystream.h、istreamwrapper.h、ostreamwrapper.h、cursorstreamwrapper.h编码与错误encodings.h、encodedstream.h、error/error.h、error/en.h扩展能力pointer.h、schema.h内存分配allocators.h内部实现internal 目录下的 biginteger、diyfp、dtoa、ieee754、itoa、meta、pow10、regex、stack、strfunc、strtod、swap 等五、安装与构建RapidJSON 是**只有头文件header-only**的 C 库安装方式极为简单。5.1 直接拷贝只需把include/rapidjson目录复制到系统或项目的 include 目录即可。在 Lynx 仓库中即表现为将整个 third_party/rapidjson 目录内嵌到工程中通过include_dirs暴露给上层使用。5.2 vcpkg可选若使用 vcpkg 依赖管理器一条命令即可安装并集成 CMakevcpkg install rapidjson5.3 依赖软件CMake通用构建工具必需Doxygen可选用于生成用户文档googletest可选用于单元测试与性能测试5.4 从源码构建测试与文档以本项目内嵌副本为基础可按官方流程构建测试与示例执行git submodule update --init获取 thirdparty 子模块google test在 RapidJSON 源码目录下创建build目录进入build目录执行cmake ..配置构建Windows 用户可用 cmake-guiWindows 下在 build 目录打开解决方案构建Linux 下在 build 目录执行make。构建成功后编译产物测试与示例二进制位于bin目录生成的文档位于 build 树中的doc/html目录。运行测试make test或使用 ctest 获取更详细的输出ctest ctest -V5.5 系统级安装与 CMake 集成构建完成后可用管理员权限执行make install按系统默认路径安装全部文件。安装后其他 CMake 项目只需在CMakeLists.txt中加入find_package(RapidJSON)即可开始使用。六、快速上手DOM 解析—修改—生成官方 readme 给出了一个最经典的完整流程示例把 JSON 字符串解析进DocumentDOM对 DOM 做一次修改再序列化回 JSON 字符串。// rapidjson/example/simpledom/simpledom.cpp #include rapidjson/document.h #include rapidjson/writer.h #include rapidjson/stringbuffer.h #include iostream using namespace rapidjson; int main() { // 1. Parse a JSON string into DOM. const char* json {\project\:\rapidjson\,\stars\:10}; Document d; d.Parse(json); // 2. Modify it by DOM. Value s d[stars]; s.SetInt(s.GetInt() 1); // 3. Stringify the DOM StringBuffer buffer; WriterStringBuffer writer(buffer); d.Accept(writer); // Output {project:rapidjson,stars:11} std::cout buffer.GetString() std::endl; return 0; }6.1 三步流程拆解解析Document d; d.Parse(json);将 JSON 文本解析为内存中的 DOM 树Document继承自GenericValueValue/Document是 DOM 的核心类型修改d[stars]以键名索引对象成员SetInt/GetInt完成数值的读取与改写。若stars不存在d[stars]会以默认值Null创建该成员这是 RapidJSON 的一个常用但易被忽视的行为序列化StringBuffer作为输出流WriterStringBuffer通过Accept(writer)以 SAX 事件方式遍历 DOM 并写出 JSON 文本最终由buffer.GetString()取出。官方 readme 特别提醒上述示例没有处理潜在错误。在实际工程中应检查d.Parse(json)的返回值例如document.Parse(json).HasParseError()并配合 error/en.h 中的GetParseErrorMsg()获取错误描述。6.2 在 Lynx 中的等价封装Lynx 在 core/base/json/json_utils.cc 中提供了与上例完全对应的工具函数strToJsonrapidjson::Document strToJson(const char* json) { rapidjson::Document document; if (document.Parse(json).HasParseError()) { printf( parse json str error: %s\n, json); return document; } return document; }而ToJsonjson_utils.cc则复刻了Writer 序列化环节std::string ToJson(const rapidjson::Value json) { rapidjson::Value msg(rapidjson::kObjectType); rapidjson::StringBuffer buffer; rapidjson::Writerrapidjson::StringBuffer writer(buffer); json.Accept(writer); std::string str buffer.GetString(); return str; }值得一提的还有 json_utils.cc 中声明的全局分配器rapidjson::MemoryPoolAllocator* global_allocate_ new rapidjson::MemoryPoolAllocator();MemoryPoolAllocator是 RapidJSON 默认的快速内存池分配器解析/构造 DOM 时从中紧凑分配内存这正是内存友好特性的底层来源。Lynx 将其提升为进程级全局实例供各模块共享同一内存池。6.3 类型查询工具json_util.h 还暴露了一组轻量类型查询函数其实现json_utils.cc展示了GenericValue的典型类型判断 APIbool IsNumber(const rapidjson::Value value) { return value.IsNumber(); } bool IsArray(const rapidjson::Value value) { return value.IsArray(); } bool IsNull(const rapidjson::Value value) { return value.IsNull(); } const char* TypeName(const rapidjson::Value value) { switch (value.GetType()) { case rapidjson::kNullType: return null; case rapidjson::kNumberType: return number; case rapidjson::kStringType: return string; case rapidjson::kTrueType: case rapidjson::kFalseType: return bool; case rapidjson::kArrayType: return array; case rapidjson::kObjectType: return object; default: return ; } }GetType()返回的枚举类型kNullType/kNumberType/kStringType/kTrueType/kFalseType/kArrayType/kObjectType是 RapidJSON 类型系统的核心DOM 的一切操作都建立在其上。七、SAX 与 DOM两套 API 的分工RapidJSON 的架构精髓在于同一库内同时提供两套 API分别对应不同的性能/易用性取舍DOM APIdocument.h将整个 JSON 解析为一棵内存树Document、Value支持随机访问、修改、增删成员适合需要频繁读写或多次操作的场景。代价是需要额外内存保存整棵树SAX APIreader.h事件驱动的流式解析解析过程中触发Null()、Bool()、Int()、String()、StartObject()、EndArray()等回调事件。SAX 解析器仅约 500 行不构建整棵树内存占用极低、延迟极低适合超大数据流或边读边处理的场景Writer / PrettyWriterwriter.h、prettywriter.hSAX 事件的生产者通过手动调用StartObject()/Key()/String()/EndObject()等方法逐步构建 JSON 文本PrettyWriter额外输出缩进与换行。SAX 与 DOM 之间通过Accept()互通任何实现了Handler接口的对象如Writer、自定义 Handler都可以接收Document的Accept()事件流。Lynx 中 Writer 的实战调试环境序列化core/renderer/utils/lynx_env.cc 中的GetDebugDescription()是 SAX Writer 的一个典型工业级用法——手工驱动事件流把一批环境变量序列化为 JSON 对象std::string LynxEnv::GetDebugDescription() { rapidjson::StringBuffer buffer; rapidjson::Writerrapidjson::StringBuffer writer(buffer); writer.StartObject(); for (Key key (Key)0; key Key::END_MARK;) { std::string key_string GetEnvKeyString(key); std::optionalstd::string value GetStringEnv(key); if (value.has_value()) { writer.Key(key_string.c_str()); writer.String((*value).c_str()); } key (Key)((uint64_t)key 1); } writer.EndObject(); std::string result buffer.GetString(); return result; }这里通过StartObject()→ 循环Key()/String()→EndObject()的事件序列优雅地规避了先构建 DOM 再序列化的中间内存开销直接向StringBuffer写出 JSON——这正是 SAX 风格 API 在真实代码中的价值体现。八、仓库内实际使用案例除了上文的工具封装RapidJSON 在 Lynx 仓库中被广泛用于 DOM 构建与业务数据交换以下案例均可直接翻阅源码验证。8.1 元素查询从 Lepus 值到 JSON DOMcore/renderer/dom/lynx_element_query.cc 展示了如何用GenericValue与AllocatorType构造异构 JSON DOM——将 Lepus 脚本值lepus::Value递归转换为rapidjson::Valuerapidjson::Value LepusValueToJson( const lepus::Value value, rapidjson::Document::AllocatorType allocator) { switch (value.Type()) { ... return rapidjson::Value(rapidjson::kNullType); ... return rapidjson::Value(value.Bool()); ... return rapidjson::Value(value.Number()); ... return rapidjson::Value(value.StdString().c_str(), allocator); ... rapidjson::Value array(rapidjson::kArrayType); ... rapidjson::Value object(rapidjson::kObjectType); object.AddMember(rapidjson::Value(pair.first.c_str(), allocator), ...); ... } return rapidjson::Value(rapidjson::kNullType); }同一文件中的AttrMapToJson、AttributesToJson、PositionInfoToJson、DumpElementlynx_element_query.cc则分别把属性表、元素属性和位置信息转换为 JSON DOM并借助rapidjson::StringRef零拷贝引用常量键名配合AddMember组装对象。这些函数共同支撑起 Lynx 的lynxElementQuery能力——以 JSON 形式向调试端返回元素树快照。8.2 模板配置解析core/renderer/tasm/config.h 直接#include third_party/rapidjson/document.h说明模板组装TASM配置的解析同样建立在 RapidJSON DOM 之上。8.3 更多引用面从仓库检索可以看到third_party/rapidjson/头文件还被core/base/androidJava 数据桥接、core/runtime/common/js_error_reporter.cc、core/renderer/events/touch_event_handler.cc、core/renderer/ui_wrapper/paintingiOS/Harmony 绘制上下文、CSS 解析器单测css_parser_token_unittest.cc、css_font_face_token_unittest.cc等大量模块引用是 Lynx 引擎内部 JSON 处理的公共基础设施。九、示例程序家族官方 readme 按能力维度列出了丰富的示例程序示例目录为 upstream 仓库的example/本内嵌副本仅含头文件与构建脚本可按需对照学习DOM APItutorialDOM API 的基础用法覆盖Value的读写、类型转换、数组与对象操作、深拷贝等全部核心技能SAX APIsimplereader使用Reader解析 JSON 时转储全部 SAX 事件condense命令行工具去除 JSON 中所有空白重新输出pretty命令行工具使用PrettyWriter输出带缩进与换行的 JSONcapitalize命令行工具将 JSON 中的字符串大写化messagereader用 SAX API 解析一条 JSON 消息serialize用 SAX API 把 C 对象序列化为 JSONjsonx实现JsonxWriter把 SAX 事件序列化为 JSONxXML 风格格式Schemaschemavalidator命令行工具用 JSON Schema 校验 JSON高级prettyautopretty的增强版自动处理任意 UTF 编码的 JSONparsebyparts基于 C11 线程实现AsyncDocumentParser可分段解析 JSONfilterkey命令行工具删除所有指定键的值filterkeydom同上功能但演示如何用 generator 填充Document。十、兼容性与测试RapidJSON 是跨平台库官方 readme 列出的已验证平台/编译器组合包括平台/编译器架构Visual C 2008/2010/2013Windows32/64-bitGNU C 3.8.xCygwin-Clang 3.4Mac OS X 与 iOS32/64-bitClang 3.4Android NDK-用户可以在自己的平台/编译器上构建并运行单元测试流程见第五节。在 Lynx 仓库中RapidJSON 的跨平台能力与 GN 构建体系配合同时服务于 Android、DarwiniOS/macOS、Harmony 等多个平台目标。十一、贡献指南与许可Issues欢迎提交 issue 与功能增强请求。提交时请提供最小可复现示例minimal reproducible examples代码比文字更容易让人理解问题所在。对于特定平台的崩溃问题请附带栈转储stack dump以及操作系统、编译器等详细信息建议先尝试断点调试说明你的发现以便基于更充分的信息展开排查。贡献流程RapidJSON 遵循通用的 fork-and-pull Git 工作流在 GitHub 上Fork仓库Clone到本地机器在 fork 上Checkout新分支并开始开发提交前测试改动确保通过全部测试包括unittest与preftest并为新特性或 bug 修复补充测试用例Commit到自己的分支Push回自己的 fork提交Pull Request供评审。注意提交 PR 前务必先从 upstream 合并最新代码。LicenseRapidJSON 采用 MIT 许可证官方 readme 建议直接拷贝以下许可声明Tencent is pleased to support the open source community by making RapidJSON available. Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. Licensed under the MIT License (the License); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://opensource.org/licenses/MIT Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an AS IS BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.仓库内副本的许可文本见 third_party/rapidjson/license.txt官方 readme 的中文版见 third_party/rapidjson/readme.zh-cn.md。十二、核心路径速查用途仓库路径官方英文 readmethird_party/rapidjson/readme.md官方中文 readmethird_party/rapidjson/readme.zh-cn.mdGN 构建配置third_party/rapidjson/BUILD.gn源文件清单third_party/rapidjson/rapidjson.gniDOM 核心third_party/rapidjson/document.hSAX 解析third_party/rapidjson/reader.h序列化 Writerthird_party/rapidjson/writer.hJSON Pointerthird_party/rapidjson/pointer.hJSON Schemathird_party/rapidjson/schema.h内存分配器third_party/rapidjson/allocators.hLynx 统一封装core/base/json/json_utils.cc、core/base/json/json_util.h元素查询序列化core/renderer/dom/lynx_element_query.cc调试环境序列化core/renderer/utils/lynx_env.cc结语RapidJSON 以header-only、双 API、低内存占用、强 Unicode 支持四项核心设计在 C JSON 库中独树一帜。在 Lynx 仓库中它作为内嵌第三方依赖通过 GN 宏配置启用 C11 能力被core/base/json统一封装后渗透到元素查询、模板配置、调试序列化等引擎关键路径。掌握其 DOM 读写与 SAX 事件流两套范式并结合仓库内真实用例strToJson/ToJson、LepusValueToJson、GetDebugDescription对照学习是在 Lynx 生态中高效处理 JSON 数据的最佳捷径。【免费下载链接】lynxEmpower the Web community and invite more to build across platforms.项目地址: https://gitcode.com/GitHub_Trending/lynx10/lynx创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表