123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 |
- #include "rapidjson/reader.h"
- #include "rapidjson/document.h"
- #include <iostream>
- // 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;
- }
|