2012-10-05 17 views
13

Necesito recuperar un objeto anidado dentro de una cadena JSON y estoy tratando de hacerlo usando rapidjson. Todo lo que he encontrado es cómo recuperar matrices y tipos básicos, pero no subobjetos. He creado el siguiente ejemplo de juguete que da un error:Recuperando un objeto anidado dentro de una cadena JSON usando 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; 
    } 
} 

Ésta es la salida cuando se ejecuta:

{ "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 

¿Cómo recupero el objeto interno para continuar mi análisis? Gracias.

Editar: Lo que necesito es obtener la representación de cadena del objeto interno para que pueda llamar a otra función que vaya a analizarlo.

Editar 2: código que permita recuperar el objeto interno como una cadena:

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; 
    } 
} 
+0

¿Significa que RapidJson no admite objetos jerárquicos? entonces solo analiza el nivel raíz?!?! –

Respuesta

7

Es necesario iterar a través de los miembros del objeto de forma manual, como GetString() sólo funciona en los miembros de cuerda, mientras que el documento [ "a"] es un Objeto. Necesita iterar a través de los miembros de ese objeto utilizando la variable MemberIterator. No tenía práctica en C * durante más de 15 años, así que sólo puedo dar una idea general de cómo debería funcionar:

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

Además, es posible que desee ver en Aceptar() método, que parece devuelve una cadena JSON de un objeto que le asignas.

+0

Sí, "Aceptar()" fue la respuesta. Permite poner el objeto interno en un escritor que llena un búfer de cadena. Entonces, es posible obtener la cadena del buffer. He editado la pregunta original con un código de trabajo. ¡Muchas gracias! – pparescasellas

3

Si el elemento es un objeto que sólo puede acceder subpropiedades con []:

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

He aquí un ejemplo de código para obtener el objeto anidado como rapidjson::Document objeto.

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; 
} 
-1

también se puede utilizar el puntero del documento:

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

y poniendo en el puntero de valor y utilizarlo

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

Esto es algo que trabajé recientemente:

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 
    }  
} 
} 

Esto puede manejar cualquier tipo de árbol JSON. Todo lo que tiene que hacer es pasar un valor como tal:

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

¡Y listo!

+1

¿Estás pegando tu misma respuesta en todas las preguntas de rapidjson? downvote –

+1

Miré en Internet para siempre y no pude encontrarlo. Solo intento ayudar. Cálmese –

Cuestiones relacionadas