Rapidjson:doc.IsObject()在解析后返回false,即使doc.GetType()返回kObjectType

时间:2017-03-08 15:38:14

标签: c++ parsing c++11 rapidjson

我正在尝试使用rapidjson加载JSON文档。解析后,断言doc.IsObject()失败,我无法理解为什么。 我绝对相信文件名是正确的,我测试了jsonContent:好的。

这是加载代码:

std::ifstream file(filename);
std::string jsonContent( (std::istreambuf_iterator<char>(file)), (std::istreambuf_iterator<char>()));
rapidjson::Document doc;
doc.Parse < rapidjson::kParseStopWhenDoneFlag, rapidjson::UTF8<> >(jsonContent.c_str(), jsonContent.length());
assert(doc.IsObject());

这是加载的JSON:

{
"version": "170301",
"lang": "en"
}

这是输出:

MyTest: /home/dev/Projects/myproject/src/loadJson.cpp:85: void  loadFile(const std::string &): Assertion `doc.IsObject()' failed.
unknown location(0): fatal error in "MyTest": signal: SIGABRT (application abort requested)

我用gdb执行了这个并获得了以下信息(断言之前的断点):

(gdb) p doc
$1 = {<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >> = {static kDefaultArrayCapacity = 16, static kDefaultObjectCapacity = 16, data_ = {s = {
        length = 2, hashcode = 2, 
        str = 0x30000006a5b48 <error: Cannot access memory at address 0x30000006a5b48>}, ss = {
        str = "\002\000\000\000\002\000\000\000H[j\000\000"}, n = {i = {i = 2, 
          padding = "\002\000\000"}, u = {u = 2, padding2 = "\002\000\000"}, i64 = 8589934594, 
        u64 = 8589934594, d = 4.2439915829186759e-314}, o = {size = 2, capacity = 2, 
        members = 0x30000006a5b48}, a = {size = 2, capacity = 2, elements = 0x30000006a5b48}, f = {
        payload = "\002\000\000\000\002\000\000\000H[j\000\000", flags = 3}}}, 
  static kDefaultStackCapacity = 1024, allocator_ = 0x7fff00000000, ownAllocator_ = 0x691460, 
  stack_ = {allocator_ = 0x691460, ownAllocator_ = 0x0, stack_ = 0x0, stackTop_ = 0x0, 
    stackEnd_ = 0x0, initialCapacity_ = 0}, parseResult_ = {code_ = **rapidjson::kParseErrorNone,** 
    offset_ = 0}}
(gdb) p doc.GetType()
$2 = rapidjson::kObjectType
(gdb) p doc.IsObject()
$3 = false
(gdb) p jsonContent 
$4 = "{\n\t\"version\": \"170301\",\n\t\"lang\": \"en\"\n}\n\n"

我尝试了here列出的所有变体,并且我得到了相同的断言失败。

3 个答案:

答案 0 :(得分:0)

我无法通过以下代码重现该问题:

#include <iostream>
#include "rapidjson/document.h"

int main() {
    rapidjson::Document doc;
    doc.Parse < rapidjson::kParseStopWhenDoneFlag, rapidjson::UTF8<> >("{\"version\": \"170301\",\"lang\": \"en\"}");
    std::cout << doc.IsObject() << std::endl;
}

答案 1 :(得分:0)

问题是您和Milo的代码可以在x86上运行。

实际上,它可能在ibm服务器上的运行时失败(就我而言)。

最容易猜测的关键是指针大小不匹配。 Rapidjson假定指针的大小不超过64位(某些平台不是这种情况),因此RAPIDJSON_ALIGN破坏了要解析的数据,从而在解析时似乎不是有效的对象。

特定的解决方案是通过编译标志(TERASPACELLP64)退回到64位大小的指针,并确保模块实际上进入了太字节空间。

还可以使用预处理程序命令#pragma datamodel (LLP64)进行正确的设置验证。

也许这些技巧会有所帮助。

答案 2 :(得分:0)

解决此问题的一个好方法是将 std::string 复制到静态分配的 char(字节)数组中。确保使用静态分配的缓冲区而不是动态调用 parse。如果您进行转换并确保遵循 JSON 标准,则 Rapidjson 将起作用。

您基本上希望将每个字符存储到一个字节槽中: [0]: '{', [1]: '"', [2]:"v", [3]: "e" ... (希望你明白这一点)。确保你没有存储类似的东西: [0]:'{', [1]:'\', [2]:""", [3]: "v" .. . 这将导致解析器出现另一组问题。

基本上,这就是 Milo 在下面的回答中所要表达的。他使用了一个静态字符串,但可以很容易地用一个静态分配的缓冲区替换,该缓冲区可以用来自 std::string 的 JSON 字符填充。