351 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			351 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #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
 |