2015-06-17 2 views
4

Я разбор JSON структуру, которая аналогична следующегоитерации и извлекать вложенный объект в JSON с помощью rapidjson

{ 
    "item1" : "value1" 
    "item2" : "value2" 
    // ... 
    "itemn" : { 
     "outernestedItem1" : { 
      "innerNestedItem1" : "valuen1" 
      "innerNestedItem2" : "valuen2" 
     } 
     // .... 
     "outernestedItemn" : { 
      "innerNestedItem1" : "valuen1" 
      "innerNestedItem2" : "valuen2" 
     } 
    } 
} 

Числа внешних вложенных элементов не является фиксированным, так что я итерацией с использованием итератора из rapidjson, внутреннего переменные -nested objects фиксированы, поэтому я могу получить доступ к ним с помощью [].

const rapidjson::Value& itemn = document["itemn"]; 
for (rapidjson::Value::ConstMemberIterator itr = itemn.MemberBegin(); 
itr != itemn.MemberEnd(); ++itr) 
{ 
    rapidjson::StringBuffer sb; 
    rapidjson::Writer<rapidjson::StringBuffer> writer(sb); 
    itr->value.Accept(writer); 

    std::cout << sb["innerNestedItem1"].GetString(); 
    std::cout << sb["innerNestedItem2"].GetString(); 
} 

но [] не разрешено использовать sb (строковый буфер), любая идея, как я могу это сделать?

Редактировать 1: Я сделал это очень неэффективно, но просто поделился решением, поэтому он может помочь кому-то придумать эффективное решение.

const rapidjson::Value& itemn = document["itemn"]; 
for (rapidjson::Value::ConstMemberIterator itr = itemn.MemberBegin(); 
itr != itemn.MemberEnd(); ++itr) 
{ 
    rapidjson::StringBuffer sb; 
    rapidjson::Writer<rapidjson::StringBuffer> writer(sb); 
    itr->value.Accept(writer); 

    //changed from here onwards 
    rapidjson::Document for_outer_nested_item; 
    std::string temp = sb.GetString(); 
    char buffer2[100000]; 
    strcpy_s(buffer2, temp.c_str()); 
    for_outer_nested_item.ParseInsitu(buffer2); 
    std::cout << executive_command["innerNestedItem1"].GetString() << std::endl; 
    std::cout << executive_command["innerNestedItem2"].GetString() << std::endl; 
} 
+0

Если 'документ [ "itemn"]' возвращает элемент всей конструкции, а затем 'документ [ "itemn"] [ "innerNestedItem1"]' должно дать вам содержание вложенного элемента внутри. Ваш подход к первому форматированию содержимого '* itr' для строки и затем попытка извлечь элементы из этих неструктурированных данных неверна, было бы легче сохранить структурированные данные. –

+0

Документ @UlrichEckhardt ["itemn"] содержит все неопределенное количество outernesteditems, а outernesteditem - фиксированный тип объекта. – Ruturaj

+0

@Ruturaj, Вы когда-нибудь выяснили более элегантное решение? – Stradigos

ответ

5

Во-первых, позвольте мне предоставить кредит MiloYip на этом link

Second-- вот что я сделал для моего проекта:

rapidjson::Document document; 
// document holds a json document retrieved from a http GET request 
// I did not include all of that in this example. I am only showing 
// the part of iterating through a nested object and retrieving members. 

std::vector<std::string> symbols; 
// holds the values I retrieve from the json document 

if (document.Parse<0>(symbol.c_str()).HasParseError()) 
    Log() << "ERROR: encountered a JSON parsing error" << std::endl; 
else { 
    // Get the nested object that contains the elements I want. 
    // In my case, the nested object in my json document was results 
    // and the values I was after were identified as "t" 
    rapidjson::Value& results = document["results"]; 
    assert(results.IsArray()); 
    for (rapidjson::SizeType i = 0; i < results.Size(); i++) { 
     // Store the value of the element in a vector. 
     symbols.emplace_back(results[i]["t"].GetString()); 
}        

Я думаю, что это довольно чистый/эффективный подход ,

2

Это что-то я в последнее время работал на:

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); 

И все готово!

2
void parseRecursive(std::string scope 
        , rapidjson::Value::ConstMemberIterator object 
        , std::unordered_map<std::string, std::string>& values) 
{ 
    if (scope.empty()) 
    { 
     scope = object->name.GetString(); 
    } 
    else 
    { 
     scope = scope + "::" + object->name.GetString(); 
    } 
    auto inElement = scope + "::"; 

    if (object->value.IsObject()) 
    { 
     for (auto it = object->value.MemberBegin(); it != object->value.MemberEnd(); ++it) 
     { 
      parseRecursive(scope, it, values); 
     } 
    } 
    else if (object->value.IsDouble()) 
    { 
     values.emplace(inElement, std::to_string(object->value.GetDouble())); 
    } 
    else if (object->value.IsInt()) 
    { 
     values.emplace(inElement, std::to_string(object->value.GetInt())); 
    } 
    else 
    { 
     LOGW("Unsuported: " << inElement << object->name.GetString()); 
    } 
} 

И начать с документом: rapidjson::Document document;

for (auto it = document.MemberBegin(); it != document.MemberEnd(); ++it) 
{ 
    parseRecursive("", it, _values); 
} 
0

a.raya203 «s сообщение https://stackoverflow.com/a/43120359/6155053 не работает для меня из коробки (не обрабатывать все типы текущей версии rapidjson реализует и, таким образом, сталкивается с ошибками, когда, например, вывод gltfs, содержащих парные разряды, и т. д.), но он привел меня на правильный путь, чтобы понять, как работает quickjson для разбора документа, поэтому я думал, что оставил бы мой (обновленный) код здесь, возможно это помогает кому-то еще ...

#include <iostream> 
#include <string> 

class JsonNodePrinter final 
{ 
public: 
    static void PrintNode(const rapidjson::Value &node, size_t indent = 0, unsigned int level = 0, const std::string& nodeName = "") 
    { 
     std::cout << GetIndentString(indent, level); 

     if (!nodeName.empty()) 
      std::cout << nodeName << ": "; 

     if (node.IsBool()) 
      std::cout << node.GetBool(); 

     else if (node.IsInt()) 
      std::cout << node.GetInt(); 

     else if (node.IsUint()) 
      std::cout << node.GetUint(); 

     else if (node.IsInt64()) 
      std::cout << node.GetInt64(); 

     else if (node.IsUint64()) 
      std::cout << node.GetUint64(); 

     else if (node.IsDouble()) 
      std::cout << node.GetDouble(); 

     else if (node.IsString()) 
      std::cout << node.GetString(); 

     else if (node.IsArray()) 
     { 
      if (!nodeName.empty()) std::cout << "\n" << GetIndentString(indent, level); 
      PrintArray(node, indent, level); 
     } 

     else if (node.IsObject()) 
     { 
      if (!nodeName.empty()) std::cout << "\n" << GetIndentString(indent, level); 
      PrintObject(node, indent, level); 
     } 

     std::cout << "\n"; 
    } 

    static void PrintObject(const rapidjson::Value &node, size_t indent = 0, unsigned int level = 0) 
    { 
     std::cout << "{\n"; 

     for (rapidjson::Value::ConstMemberIterator childNode = node.MemberBegin(); childNode != node.MemberEnd(); ++childNode) 
     { 
      PrintNode(childNode->value, indent, level + 1, childNode->name.GetString()); 
     } 

     std::cout << GetIndentString(indent, level) << "}"; 
    } 

    static void PrintArray(const rapidjson::Value& node, size_t indent = 0, unsigned int level = 0) 
    { 
     std::cout << "[\n"; 

     for (rapidjson::SizeType i = 0; i < node.Size(); ++i) 
     { 
      PrintNode(node[i], indent, level + 1); 
     } 

     std::cout << GetIndentString(indent, level) << "]"; 
    } 

    static std::string GetIndentString(size_t indent = 0, unsigned int level = 0) 
    { 
     return std::move(std::string(level * indent, ' ')); 
    } 
}; 

Используйте его как

#include "3rdParty/rapidjson/document.h" 

rapidjson::Document document; 
{ 
    document.Parse(FileHelper::ReadString(filePath)->c_str()); 
} 

if (!document.HasParseError()) 
{ 
    JsonNodePrinter::PrintNode(document, 4); 
} 
Смежные вопросы