【问题标题】:Retrieving a nested object inside a JSON string using rapidjson使用 rapidjson 检索 JSON 字符串中的嵌套对象
【发布时间】:2012-10-05 08:56:03
【问题描述】:

我需要在 JSON 字符串中检索一个嵌套对象,我正在尝试使用 rapidjson 来完成它。我发现的只是如何检索数组和基本类型,而不是子对象。我创建了以下给出错误的玩具示例:

rapidjson::Document document;
std::string test =  " { \"a\": { \"z\" : 21 } } ";
std::cout << test << std::endl;
if ( document.Parse<0>( test.c_str() ).HasParseError() ) {
    std::cout << "Parsing error" << std::endl;
} else {
    if ( document[ "a" ].IsObject() ) {
        std::cout << "OK" << std::endl;
        std::cout << document[ "a" ].GetString() << std::endl;
    }
}

这是执行时的输出:

{ "a": { "z" : 21 } } 
OK
JSONTest: ../rapidjson/document.h:441: const typename Encoding::Ch* rapidjson::GenericValue<Encoding, Allocator>::GetString() const [with Encoding = rapidjson::UTF8<char>, Allocator = rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>]: Assertion `IsString()' failed. Aborted

如何检索内部对象以继续解析?谢谢。

编辑:我需要的是获取内部对象的字符串表示,这样我就可以调用另一个函数来解析它。

编辑 2:允许将内部对象检索为字符串的代码:

rapidjson::Document document;
std::string test =  "{\"a\":{\"z\":21}} ";
if ( document.Parse<0>( test.c_str() ).HasParseError() ) {
    std::cout << "Error parsing" << std::endl;
} else {
    if ( document[ "a" ].IsObject() ) {
        rapidjson::StringBuffer sb;
        rapidjson::Writer<rapidjson::StringBuffer> writer( sb );
        document[ "a" ].Accept( writer );
        std::cout << sb.GetString() << std::endl;
    }
}

【问题讨论】:

  • 是不是说RapidJson不支持分层对象?所以它只解析根级别?!?!
  • 是edit2对递归很有用,可以将内部的json对象转成字符串,可以递归解析。

标签: c++ json rapidjson


【解决方案1】:

如果元素是一个对象,您可以使用 [] 访问子属性:

for (SizeType i = 0; i < layers.Size(); i++){   
  cout << layers[i]["name"].GetString() << endl;
}

【讨论】:

    【解决方案2】:

    在 rapidjson 中实现了另一种很棒的方法 - JSON Pointers。它们具有实验状态,根据文档应包含在 v.1.1 中。无论如何,这种方法看起来像 XML 的 XPATH,所以要获得嵌套值,我们可以使用类似

    的语法
    Value* tmpValue = GetValueByPointer(doc, "/result/job/blob");
    

    我尝试了这个功能,在我看来这比迭代器更好。

    【讨论】:

      【解决方案3】:

      您需要手动遍历对象的成员,因为 GetString() 仅适用于字符串成员,而 document["a"] 是一个对象。您需要使用 MemberIterator 变量遍历该对象的成员。我有超过 15 年的 C* 实践经验,所以我只能大致了解它应该如何工作:

      for (MemberIterator m = document["a"].MemberBegin(); m != document["a"].MemberEnd(); ++m) {
          std::cout << m.name << " " << (m.IsNumber()?m.GetNumber():m.GetString()) << endl;
      }
      

      另外,你可能想看看 Accept() 方法,它似乎返回你给它的对象的 JSON 字符串。

      【讨论】:

      • 是的,“Accept()”就是答案。它允许将内部对象放入填充字符串缓冲区的写入器中。然后,可以从缓冲区中获取字符串。我已经用工作代码编辑了原始问题。非常感谢!
      【解决方案4】:

      这是我最近在做的事情:

      void enter(const Value &obj, size_t indent = 0) { //print JSON tree
      
      if (obj.IsObject()) { //check if object
          for (Value::ConstMemberIterator itr = obj.MemberBegin(); itr != obj.MemberEnd(); ++itr) {   //iterate through object   
              const Value& objName = obj[itr->name.GetString()]; //make object value
      
              for (size_t i = 0; i != indent; ++i) //indent
                  cout << " ";
      
              cout << itr->name.GetString() << ": "; //key name
      
              if (itr->value.IsNumber()) //if integer
                  std::cout << itr->value.GetInt() ;
      
              else if (itr->value.IsString()) //if string
                  std::cout << itr->value.GetString();
      
      
              else if (itr->value.IsBool()) //if bool
                  std::cout << itr->value.GetBool();
      
              else if (itr->value.IsArray()){ //if array
      
                  for (SizeType i = 0; i < itr->value.Size(); i++) {
                      if (itr->value[i].IsNumber()) //if array value integer
                          std::cout << itr->value[i].GetInt() ;
      
                      else if (itr->value[i].IsString()) //if array value string
                          std::cout << itr->value[i].GetString() ;
      
                      else if (itr->value[i].IsBool()) //if array value bool
                          std::cout << itr->value[i].GetBool() ;
      
                      else if (itr->value[i].IsObject()){ //if array value object
                          cout << "\n  ";
                          const Value& m = itr->value[i]; 
                          for (auto& v : m.GetObject()) { //iterate through array object
                              if (m[v.name.GetString()].IsString()) //if array object value is string
                                  cout << v.name.GetString() << ": " <<   m[v.name.GetString()].GetString();
                              else //if array object value is integer
                                  cout << v.name.GetString() << ": "  <<  m[v.name.GetString()].GetInt();
      
                             cout <<  "\t"; //indent
                          }
                      }
                      cout <<  "\t"; //indent
                  }
              }
      
              cout << endl; 
              enter(objName, indent + 1); //if couldn't find in object, enter object and repeat process recursively 
          }     
      }
      }
      

      这可以处理任何类型的 JSON 树。您所要做的就是传递一个这样的值:

      Value v = document.GetObject();
      Value& m= v;
      enter(m);
      

      你就完成了!

      【讨论】:

      • 您是否只是在所有 rapidjson 问题上粘贴相同的答案?投反对票
      • 我一直在互联网上寻找这个并找不到它。只是想帮忙。冷静
      【解决方案5】:

      这是一个将嵌套对象作为rapidjson::Document 对象的示例代码。

      Document get_nested(Document &d, std::string key){
      rapidjson::StringBuffer buffer;
      const char *key_ctr = key.c_str();
      
      assert(d[key_ctr].IsObject());
      
      rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
      d[key_ctr].Accept(writer);
      
      rapidjson::Document result;
      rapidjson::StringStream s(buffer.GetString());
      result.ParseStream(s);
      
      return result;
      }
      

      【讨论】:

        【解决方案6】:

        可以使用指针来获取子对象:

        Value& a = *GetValueByPointer(document, "/a");
        int z = a["z"].GetInt();
        

        【讨论】:

        • 欢迎来到 Stack Overflow!请不要只用源代码回答。尝试对您的解决方案如何工作提供一个很好的描述。请参阅:How do I write a good answer?。谢谢
        【解决方案7】:
        GenericObject doc2 = document["a"].GetObjectW();
        int z = doc2["z"].GetInt();    
        

        使用用于 c++ 的 rapidJson lib 解析 json 内嵌套对象的简单方法..

        【讨论】:

          【解决方案8】:

          你也可以使用Document的指针:

          Document *document= new Document();
          document->parse( test.c_str());
          

          并放入Value指针并使用它

          Value *val= document;
          val = &(*val)["a"];
          val = &(*val)["z"];
          cout << val->GetString();
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2022-01-08
            • 1970-01-01
            • 2017-08-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多