| #include "rapidjson/reader.h" |
| #include "rapidjson/document.h" |
| #include <iostream> |
| |
| RAPIDJSON_DIAG_PUSH |
| #ifdef __GNUC__ |
| RAPIDJSON_DIAG_OFF(effc++) |
| #endif |
| |
| // This example demonstrates JSON token-by-token parsing with an API that is |
| // more direct; you don't need to design your logic around a handler object and |
| // callbacks. Instead, you retrieve values from the JSON stream by calling |
| // GetInt(), GetDouble(), GetString() and GetBool(), traverse into structures |
| // by calling EnterObject() and EnterArray(), and skip over unwanted data by |
| // calling SkipValue(). When you know your JSON's structure, this can be quite |
| // convenient. |
| // |
| // If you aren't sure of what's next in the JSON data, you can use PeekType() and |
| // PeekValue() to look ahead to the next object before reading it. |
| // |
| // If you call the wrong retrieval method--e.g. GetInt when the next JSON token is |
| // not an int, EnterObject or EnterArray when there isn't actually an object or array |
| // to read--the stream parsing will end immediately and no more data will be delivered. |
| // |
| // After calling EnterObject, you retrieve keys via NextObjectKey() and values via |
| // the normal getters. When NextObjectKey() returns null, you have exited the |
| // object, or you can call SkipObject() to skip to the end of the object |
| // immediately. If you fetch the entire object (i.e. NextObjectKey() returned null), |
| // you should not call SkipObject(). |
| // |
| // After calling EnterArray(), you must alternate between calling NextArrayValue() |
| // to see if the array has more data, and then retrieving values via the normal |
| // getters. You can call SkipArray() to skip to the end of the array immediately. |
| // If you fetch the entire array (i.e. NextArrayValue() returned null), |
| // you should not call SkipArray(). |
| // |
| // This parser uses in-situ strings, so the JSON buffer will be altered during the |
| // parse. |
| |
| using namespace rapidjson; |
| |
| |
| class LookaheadParserHandler { |
| public: |
| bool Null() { st_ = kHasNull; v_.SetNull(); return true; } |
| bool Bool(bool b) { st_ = kHasBool; v_.SetBool(b); return true; } |
| bool Int(int i) { st_ = kHasNumber; v_.SetInt(i); return true; } |
| bool Uint(unsigned u) { st_ = kHasNumber; v_.SetUint(u); return true; } |
| bool Int64(int64_t i) { st_ = kHasNumber; v_.SetInt64(i); return true; } |
| bool Uint64(uint64_t u) { st_ = kHasNumber; v_.SetUint64(u); return true; } |
| bool Double(double d) { st_ = kHasNumber; v_.SetDouble(d); return true; } |
| bool RawNumber(const char*, SizeType, bool) { return false; } |
| bool String(const char* str, SizeType length, bool) { st_ = kHasString; v_.SetString(str, length); return true; } |
| bool StartObject() { st_ = kEnteringObject; return true; } |
| bool Key(const char* str, SizeType length, bool) { st_ = kHasKey; v_.SetString(str, length); return true; } |
| bool EndObject(SizeType) { st_ = kExitingObject; return true; } |
| bool StartArray() { st_ = kEnteringArray; return true; } |
| bool EndArray(SizeType) { st_ = kExitingArray; return true; } |
| |
| protected: |
| LookaheadParserHandler(char* str); |
| void ParseNext(); |
| |
| protected: |
| enum LookaheadParsingState { |
| kInit, |
| kError, |
| kHasNull, |
| kHasBool, |
| kHasNumber, |
| kHasString, |
| kHasKey, |
| kEnteringObject, |
| kExitingObject, |
| kEnteringArray, |
| kExitingArray |
| }; |
| |
| Value v_; |
| LookaheadParsingState st_; |
| Reader r_; |
| InsituStringStream ss_; |
| |
| static const int parseFlags = kParseDefaultFlags | kParseInsituFlag; |
| }; |
| |
| LookaheadParserHandler::LookaheadParserHandler(char* str) : v_(), st_(kInit), r_(), ss_(str) { |
| r_.IterativeParseInit(); |
| ParseNext(); |
| } |
| |
| void LookaheadParserHandler::ParseNext() { |
| if (r_.HasParseError()) { |
| st_ = kError; |
| return; |
| } |
| |
| r_.IterativeParseNext<parseFlags>(ss_, *this); |
| } |
| |
| class LookaheadParser : protected LookaheadParserHandler { |
| public: |
| LookaheadParser(char* str) : LookaheadParserHandler(str) {} |
| |
| bool EnterObject(); |
| bool EnterArray(); |
| const char* NextObjectKey(); |
| bool NextArrayValue(); |
| int GetInt(); |
| double GetDouble(); |
| const char* GetString(); |
| bool GetBool(); |
| void GetNull(); |
| |
| void SkipObject(); |
| void SkipArray(); |
| void SkipValue(); |
| Value* PeekValue(); |
| int PeekType(); // returns a rapidjson::Type, or -1 for no value (at end of object/array) |
| |
| bool IsValid() { return st_ != kError; } |
| |
| protected: |
| void SkipOut(int depth); |
| }; |
| |
| bool LookaheadParser::EnterObject() { |
| if (st_ != kEnteringObject) { |
| st_ = kError; |
| return false; |
| } |
| |
| ParseNext(); |
| return true; |
| } |
| |
| bool LookaheadParser::EnterArray() { |
| if (st_ != kEnteringArray) { |
| st_ = kError; |
| return false; |
| } |
| |
| ParseNext(); |
| return true; |
| } |
| |
| const char* LookaheadParser::NextObjectKey() { |
| if (st_ == kHasKey) { |
| const char* result = v_.GetString(); |
| ParseNext(); |
| return result; |
| } |
| |
| if (st_ != kExitingObject) { |
| st_ = kError; |
| return 0; |
| } |
| |
| ParseNext(); |
| return 0; |
| } |
| |
| bool LookaheadParser::NextArrayValue() { |
| if (st_ == kExitingArray) { |
| ParseNext(); |
| return false; |
| } |
| |
| if (st_ == kError || st_ == kExitingObject || st_ == kHasKey) { |
| st_ = kError; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| int LookaheadParser::GetInt() { |
| if (st_ != kHasNumber || !v_.IsInt()) { |
| st_ = kError; |
| return 0; |
| } |
| |
| int result = v_.GetInt(); |
| ParseNext(); |
| return result; |
| } |
| |
| double LookaheadParser::GetDouble() { |
| if (st_ != kHasNumber) { |
| st_ = kError; |
| return 0.; |
| } |
| |
| double result = v_.GetDouble(); |
| ParseNext(); |
| return result; |
| } |
| |
| bool LookaheadParser::GetBool() { |
| if (st_ != kHasBool) { |
| st_ = kError; |
| return false; |
| } |
| |
| bool result = v_.GetBool(); |
| ParseNext(); |
| return result; |
| } |
| |
| void LookaheadParser::GetNull() { |
| if (st_ != kHasNull) { |
| st_ = kError; |
| return; |
| } |
| |
| ParseNext(); |
| } |
| |
| const char* LookaheadParser::GetString() { |
| if (st_ != kHasString) { |
| st_ = kError; |
| return 0; |
| } |
| |
| const char* result = v_.GetString(); |
| ParseNext(); |
| return result; |
| } |
| |
| void LookaheadParser::SkipOut(int depth) { |
| do { |
| if (st_ == kEnteringArray || st_ == kEnteringObject) { |
| ++depth; |
| } |
| else if (st_ == kExitingArray || st_ == kExitingObject) { |
| --depth; |
| } |
| else if (st_ == kError) { |
| return; |
| } |
| |
| ParseNext(); |
| } |
| while (depth > 0); |
| } |
| |
| void LookaheadParser::SkipValue() { |
| SkipOut(0); |
| } |
| |
| void LookaheadParser::SkipArray() { |
| SkipOut(1); |
| } |
| |
| void LookaheadParser::SkipObject() { |
| SkipOut(1); |
| } |
| |
| Value* LookaheadParser::PeekValue() { |
| if (st_ >= kHasNull && st_ <= kHasKey) { |
| return &v_; |
| } |
| |
| return 0; |
| } |
| |
| int LookaheadParser::PeekType() { |
| if (st_ >= kHasNull && st_ <= kHasKey) { |
| return v_.GetType(); |
| } |
| |
| if (st_ == kEnteringArray) { |
| return kArrayType; |
| } |
| |
| if (st_ == kEnteringObject) { |
| return kObjectType; |
| } |
| |
| return -1; |
| } |
| |
| //------------------------------------------------------------------------- |
| |
| int main() { |
| using namespace std; |
| |
| char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null," |
| "\"i\":123, \"pi\": 3.1416, \"a\":[-1, 2, 3, 4, \"array\", []], \"skipArrays\":[1, 2, [[[3]]]], " |
| "\"skipObject\":{ \"i\":0, \"t\":true, \"n\":null, \"d\":123.45 }, " |
| "\"skipNested\":[[[[{\"\":0}, {\"\":[-9.87]}]]], [], []], " |
| "\"skipString\":\"zzz\", \"reachedEnd\":null, \"t\":true }"; |
| |
| LookaheadParser r(json); |
| |
| RAPIDJSON_ASSERT(r.PeekType() == kObjectType); |
| |
| r.EnterObject(); |
| while (const char* key = r.NextObjectKey()) { |
| if (0 == strcmp(key, "hello")) { |
| RAPIDJSON_ASSERT(r.PeekType() == kStringType); |
| cout << key << ":" << r.GetString() << endl; |
| } |
| else if (0 == strcmp(key, "t") || 0 == strcmp(key, "f")) { |
| RAPIDJSON_ASSERT(r.PeekType() == kTrueType || r.PeekType() == kFalseType); |
| cout << key << ":" << r.GetBool() << endl; |
| continue; |
| } |
| else if (0 == strcmp(key, "n")) { |
| RAPIDJSON_ASSERT(r.PeekType() == kNullType); |
| r.GetNull(); |
| cout << key << endl; |
| continue; |
| } |
| else if (0 == strcmp(key, "pi")) { |
| RAPIDJSON_ASSERT(r.PeekType() == kNumberType); |
| cout << key << ":" << r.GetDouble() << endl; |
| continue; |
| } |
| else if (0 == strcmp(key, "a")) { |
| RAPIDJSON_ASSERT(r.PeekType() == kArrayType); |
| |
| r.EnterArray(); |
| |
| cout << key << ":[ "; |
| while (r.NextArrayValue()) { |
| if (r.PeekType() == kNumberType) { |
| cout << r.GetDouble() << " "; |
| } |
| else if (r.PeekType() == kStringType) { |
| cout << r.GetString() << " "; |
| } |
| else { |
| r.SkipArray(); |
| break; |
| } |
| } |
| |
| cout << "]" << endl; |
| } |
| else { |
| cout << key << ":skipped" << endl; |
| r.SkipValue(); |
| } |
| } |
| |
| return 0; |
| } |
| |
| RAPIDJSON_DIAG_POP |