使用RapidJSON解析JSON Schema时遭遇kParseErrorDocumentRootNotSingular错误排查求助
我正在使用RapidJSON解析JSON文件,尝试通过rapidjson::SchemaDocument创建JSON Schema来验证接收的JSON文件。但当我尝试构造由liquid-technologies.com网站生成的Schema文档时,收到了错误码2,该错误表明我试图解析的JSON(Schema)文档存在多个根节点,尽管实际该文档只有一个根节点。
我尝试解析的Schema文档如下:
{ "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "title": { "type": "string" }, "pay": { "type": "number" }, "country": { "type": "string" }, "employer": { "type": "object", "properties": { "name": { "type": "string" }, "workforce": { "type": "integer" }, "officelocation": { "type": "string" } }, "required": [ "name", "workforce", "officelocation" ] }, "location": { "type": "string" }, "flexibleHours": { "type": "boolean" }, "description": { "type": "string" } }, "required": [ "title", "pay", "country", "employer", "location", "flexibleHours", "description" ] }
我的代码如下:
std::string schemaJson = readFile("../jsonschemas/postjobschema.json"); rapidjson::Document sd; if (sd.Parse(schemaJson.c_str()).HasParseError()) { std::cout << "Schema has parse errors" << std::endl; if (sd.GetParseError() == rapidjson::kParseErrorDocumentRootNotSingular) std::cout << "There are multiple roots" << std::endl; }
请问是我的Schema文档存在错误,还是我的代码实现有问题?
首先可以确定的是:你提供的JSON Schema本身是完全合法的,它只有一个根对象,符合JSON规范,不会触发“多个根节点”的错误。问题大概率出在文件读取环节,或者你获取到的schemaJson内容不纯净。
下面是你可以排查的几个方向:
1. 先确认读取到的schemaJson内容是否正确
RapidJSON的kParseErrorDocumentRootNotSingular错误通常是因为解析的字符串里包含了多个独立的JSON结构(比如一个对象之后又跟着另一个对象/数组),或者有多余的无效字符干扰了解析。
你可以在代码里添加一行输出,直接打印读取到的内容:
std::cout << "Raw schema content:\n" << schemaJson << "\n--- End of content ---" << std::endl;
检查输出的内容是否和你提供的Schema完全一致:
- 有没有末尾多了额外的字符(比如换行后的另一个
{}、空行或者乱码)? - 有没有开头/中间出现了意外的字符(比如UTF-8 BOM?不过RapidJSON默认可以处理UTF-8,但BOM可能会导致解析异常)?
- 有没有文件被意外追加了其他JSON内容?
2. 检查readFile函数的实现
很多时候这类问题都是读取函数的bug导致的,比如:
- 没有正确读取整个文件,或者读取时混入了多余的字节;
- 文本模式读取时,换行符转换导致的问题(不过JSON对换行符不敏感,但极端情况可能有影响);
- 没有检查文件是否成功打开(比如文件路径错误,导致读取到空字符串或者乱码)。
举个正确的文件读取实现参考,你可以对比一下自己的readFile:
#include <fstream> #include <string> std::string readFile(const std::string& filePath) { std::ifstream file(filePath, std::ios::binary | std::ios::ate); if (!file.is_open()) { // 记得处理文件打开失败的情况! throw std::runtime_error("Failed to open file: " + filePath); } std::streamsize size = file.tellg(); std::string content(size, '\0'); file.seekg(0, std::ios::beg); file.read(&content[0], size); return content; }
这个实现用二进制模式读取,确保不会修改文件中的任何字节,并且一次性读取整个文件,避免逐行读取可能带来的问题。
3. 验证文件本身的完整性
直接用文本编辑器打开postjobschema.json文件,检查:
- 文件末尾有没有多余的空行或者字符?
- 有没有不小心粘贴了两份Schema内容?
- 文件编码是不是UTF-8(不含BOM)?有些编辑器保存时会自动添加UTF-8 BOM,虽然大部分解析器可以处理,但RapidJSON默认不忽略BOM,可能会导致解析异常。
最后
如果排查后发现读取的内容完全正确,那可以尝试用RapidJSON的ParseInsitu函数替代Parse,或者检查是否有其他代码修改了schemaJson的内容。不过根据经验,90%以上的这类问题都是文件读取或者文件本身的内容问题。
内容的提问来源于stack exchange,提问作者Khalid Al Hajri

