2012-10-05 20 views
13

Potrzebuję pobrać zagnieżdżony obiekt wewnątrz łańcucha JSON i próbuję to zrobić za pomocą rapidjson. Wszystko, co udało mi się znaleźć, to sposób pobierania tablic i podstawowych typów, ale nie pod-obiektów. Stworzyłem następujący przykład zabawki, które daje błąd:Pobieranie obiektu zagnieżdżonego wewnątrz łańcucha JSON przy użyciu 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; 
    } 
} 

To jest wyjście, gdy wykonywane:

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

Jak mogę odzyskać wewnętrzną obiektu, aby kontynuować moją analizowania? Dzięki.

Edit: Co potrzebne jest do uzyskania reprezentacji ciąg wewnętrznej obiektu, więc mogę wywołać inną funkcję, która zamierza je przetwarzać.

Edycja 2: kod, który pozwala odzyskać wewnętrzną obiektu jako ciąg znaków:

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

Czy to oznacza, że ​​RapidJson nie obsługuje obiektów hierarchicznych? więc analizuje tylko poziom główny?!?! –

Odpowiedz

7

Trzeba iterację członków obiektu ręcznie, jak GetString() działa tylko na członków smyczkowych, natomiast dokumencie [ "a"] jest obiektem. Musisz iterować przez członków tego obiektu przy użyciu zmiennej MemberIterator. Nie miałem praktyki w C * przez ponad 15 lat, więc mogę tylko dać ogólne pojęcie o tym, jak to powinno działać:

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

Ponadto, warto spojrzeć na Accept() metoda wydaje Zwróć ciąg znaków JSON obiektu, który mu podasz.

+0

Tak, "Accept()" było odpowiedzią. Pozwala umieścić obiekt wewnętrzny w pisarzu, który wypełnia bufor stringów. Następnie można uzyskać ciąg z bufora. Edytowałem oryginalne pytanie z działającym kodem. Wielkie dzięki! – pparescasellas

3

Jeśli element jest obiektem można po prostu przejść podrzędne z []:

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

Oto jeden przykład kodu, aby uzyskać zagnieżdżonego obiektu jako rapidjson::Document obiektu.

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

można również użyć wskaźnika dokumentu:

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

i wprowadzenie wskaźnika Wartość i używać go

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

To jest coś, co niedawno pracował nad:

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

Może obsłużyć dowolny typ drzewa JSON. Wystarczy podać wartość jako taką:

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

I gotowe!

+1

Czy właśnie wklejasz tę samą odpowiedź na wszystkie pytania rapidjson? downvote –

+1

Patrzyłem w Internecie na zawsze i nie mogłem go znaleźć. Próbuję ci pomóc. Uspokój się –

Powiązane problemy