lookaheadparser.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. #include "rapidjson/reader.h"
  2. #include "rapidjson/document.h"
  3. #include <iostream>
  4. RAPIDJSON_DIAG_PUSH
  5. #ifdef __GNUC__
  6. RAPIDJSON_DIAG_OFF(effc++)
  7. #endif
  8. // This example demonstrates JSON token-by-token parsing with an API that is
  9. // more direct; you don't need to design your logic around a handler object and
  10. // callbacks. Instead, you retrieve values from the JSON stream by calling
  11. // GetInt(), GetDouble(), GetString() and GetBool(), traverse into structures
  12. // by calling EnterObject() and EnterArray(), and skip over unwanted data by
  13. // calling SkipValue(). When you know your JSON's structure, this can be quite
  14. // convenient.
  15. //
  16. // If you aren't sure of what's next in the JSON data, you can use PeekType() and
  17. // PeekValue() to look ahead to the next object before reading it.
  18. //
  19. // If you call the wrong retrieval method--e.g. GetInt when the next JSON token is
  20. // not an int, EnterObject or EnterArray when there isn't actually an object or array
  21. // to read--the stream parsing will end immediately and no more data will be delivered.
  22. //
  23. // After calling EnterObject, you retrieve keys via NextObjectKey() and values via
  24. // the normal getters. When NextObjectKey() returns null, you have exited the
  25. // object, or you can call SkipObject() to skip to the end of the object
  26. // immediately. If you fetch the entire object (i.e. NextObjectKey() returned null),
  27. // you should not call SkipObject().
  28. //
  29. // After calling EnterArray(), you must alternate between calling NextArrayValue()
  30. // to see if the array has more data, and then retrieving values via the normal
  31. // getters. You can call SkipArray() to skip to the end of the array immediately.
  32. // If you fetch the entire array (i.e. NextArrayValue() returned null),
  33. // you should not call SkipArray().
  34. //
  35. // This parser uses in-situ strings, so the JSON buffer will be altered during the
  36. // parse.
  37. using namespace rapidjson;
  38. class LookaheadParserHandler {
  39. public:
  40. bool Null() { st_ = kHasNull; v_.SetNull(); return true; }
  41. bool Bool(bool b) { st_ = kHasBool; v_.SetBool(b); return true; }
  42. bool Int(int i) { st_ = kHasNumber; v_.SetInt(i); return true; }
  43. bool Uint(unsigned u) { st_ = kHasNumber; v_.SetUint(u); return true; }
  44. bool Int64(int64_t i) { st_ = kHasNumber; v_.SetInt64(i); return true; }
  45. bool Uint64(uint64_t u) { st_ = kHasNumber; v_.SetUint64(u); return true; }
  46. bool Double(double d) { st_ = kHasNumber; v_.SetDouble(d); return true; }
  47. bool RawNumber(const char*, SizeType, bool) { return false; }
  48. bool String(const char* str, SizeType length, bool) { st_ = kHasString; v_.SetString(str, length); return true; }
  49. bool StartObject() { st_ = kEnteringObject; return true; }
  50. bool Key(const char* str, SizeType length, bool) { st_ = kHasKey; v_.SetString(str, length); return true; }
  51. bool EndObject(SizeType) { st_ = kExitingObject; return true; }
  52. bool StartArray() { st_ = kEnteringArray; return true; }
  53. bool EndArray(SizeType) { st_ = kExitingArray; return true; }
  54. protected:
  55. LookaheadParserHandler(char* str);
  56. void ParseNext();
  57. protected:
  58. enum LookaheadParsingState {
  59. kInit,
  60. kError,
  61. kHasNull,
  62. kHasBool,
  63. kHasNumber,
  64. kHasString,
  65. kHasKey,
  66. kEnteringObject,
  67. kExitingObject,
  68. kEnteringArray,
  69. kExitingArray
  70. };
  71. Value v_;
  72. LookaheadParsingState st_;
  73. Reader r_;
  74. InsituStringStream ss_;
  75. static const int parseFlags = kParseDefaultFlags | kParseInsituFlag;
  76. };
  77. LookaheadParserHandler::LookaheadParserHandler(char* str) : v_(), st_(kInit), r_(), ss_(str) {
  78. r_.IterativeParseInit();
  79. ParseNext();
  80. }
  81. void LookaheadParserHandler::ParseNext() {
  82. if (r_.HasParseError()) {
  83. st_ = kError;
  84. return;
  85. }
  86. r_.IterativeParseNext<parseFlags>(ss_, *this);
  87. }
  88. class LookaheadParser : protected LookaheadParserHandler {
  89. public:
  90. LookaheadParser(char* str) : LookaheadParserHandler(str) {}
  91. bool EnterObject();
  92. bool EnterArray();
  93. const char* NextObjectKey();
  94. bool NextArrayValue();
  95. int GetInt();
  96. double GetDouble();
  97. const char* GetString();
  98. bool GetBool();
  99. void GetNull();
  100. void SkipObject();
  101. void SkipArray();
  102. void SkipValue();
  103. Value* PeekValue();
  104. int PeekType(); // returns a rapidjson::Type, or -1 for no value (at end of object/array)
  105. bool IsValid() { return st_ != kError; }
  106. protected:
  107. void SkipOut(int depth);
  108. };
  109. bool LookaheadParser::EnterObject() {
  110. if (st_ != kEnteringObject) {
  111. st_ = kError;
  112. return false;
  113. }
  114. ParseNext();
  115. return true;
  116. }
  117. bool LookaheadParser::EnterArray() {
  118. if (st_ != kEnteringArray) {
  119. st_ = kError;
  120. return false;
  121. }
  122. ParseNext();
  123. return true;
  124. }
  125. const char* LookaheadParser::NextObjectKey() {
  126. if (st_ == kHasKey) {
  127. const char* result = v_.GetString();
  128. ParseNext();
  129. return result;
  130. }
  131. if (st_ != kExitingObject) {
  132. st_ = kError;
  133. return 0;
  134. }
  135. ParseNext();
  136. return 0;
  137. }
  138. bool LookaheadParser::NextArrayValue() {
  139. if (st_ == kExitingArray) {
  140. ParseNext();
  141. return false;
  142. }
  143. if (st_ == kError || st_ == kExitingObject || st_ == kHasKey) {
  144. st_ = kError;
  145. return false;
  146. }
  147. return true;
  148. }
  149. int LookaheadParser::GetInt() {
  150. if (st_ != kHasNumber || !v_.IsInt()) {
  151. st_ = kError;
  152. return 0;
  153. }
  154. int result = v_.GetInt();
  155. ParseNext();
  156. return result;
  157. }
  158. double LookaheadParser::GetDouble() {
  159. if (st_ != kHasNumber) {
  160. st_ = kError;
  161. return 0.;
  162. }
  163. double result = v_.GetDouble();
  164. ParseNext();
  165. return result;
  166. }
  167. bool LookaheadParser::GetBool() {
  168. if (st_ != kHasBool) {
  169. st_ = kError;
  170. return false;
  171. }
  172. bool result = v_.GetBool();
  173. ParseNext();
  174. return result;
  175. }
  176. void LookaheadParser::GetNull() {
  177. if (st_ != kHasNull) {
  178. st_ = kError;
  179. return;
  180. }
  181. ParseNext();
  182. }
  183. const char* LookaheadParser::GetString() {
  184. if (st_ != kHasString) {
  185. st_ = kError;
  186. return 0;
  187. }
  188. const char* result = v_.GetString();
  189. ParseNext();
  190. return result;
  191. }
  192. void LookaheadParser::SkipOut(int depth) {
  193. do {
  194. if (st_ == kEnteringArray || st_ == kEnteringObject) {
  195. ++depth;
  196. }
  197. else if (st_ == kExitingArray || st_ == kExitingObject) {
  198. --depth;
  199. }
  200. else if (st_ == kError) {
  201. return;
  202. }
  203. ParseNext();
  204. }
  205. while (depth > 0);
  206. }
  207. void LookaheadParser::SkipValue() {
  208. SkipOut(0);
  209. }
  210. void LookaheadParser::SkipArray() {
  211. SkipOut(1);
  212. }
  213. void LookaheadParser::SkipObject() {
  214. SkipOut(1);
  215. }
  216. Value* LookaheadParser::PeekValue() {
  217. if (st_ >= kHasNull && st_ <= kHasKey) {
  218. return &v_;
  219. }
  220. return 0;
  221. }
  222. int LookaheadParser::PeekType() {
  223. if (st_ >= kHasNull && st_ <= kHasKey) {
  224. return v_.GetType();
  225. }
  226. if (st_ == kEnteringArray) {
  227. return kArrayType;
  228. }
  229. if (st_ == kEnteringObject) {
  230. return kObjectType;
  231. }
  232. return -1;
  233. }
  234. //-------------------------------------------------------------------------
  235. int main() {
  236. using namespace std;
  237. char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null,"
  238. "\"i\":123, \"pi\": 3.1416, \"a\":[-1, 2, 3, 4, \"array\", []], \"skipArrays\":[1, 2, [[[3]]]], "
  239. "\"skipObject\":{ \"i\":0, \"t\":true, \"n\":null, \"d\":123.45 }, "
  240. "\"skipNested\":[[[[{\"\":0}, {\"\":[-9.87]}]]], [], []], "
  241. "\"skipString\":\"zzz\", \"reachedEnd\":null, \"t\":true }";
  242. LookaheadParser r(json);
  243. RAPIDJSON_ASSERT(r.PeekType() == kObjectType);
  244. r.EnterObject();
  245. while (const char* key = r.NextObjectKey()) {
  246. if (0 == strcmp(key, "hello")) {
  247. RAPIDJSON_ASSERT(r.PeekType() == kStringType);
  248. cout << key << ":" << r.GetString() << endl;
  249. }
  250. else if (0 == strcmp(key, "t") || 0 == strcmp(key, "f")) {
  251. RAPIDJSON_ASSERT(r.PeekType() == kTrueType || r.PeekType() == kFalseType);
  252. cout << key << ":" << r.GetBool() << endl;
  253. continue;
  254. }
  255. else if (0 == strcmp(key, "n")) {
  256. RAPIDJSON_ASSERT(r.PeekType() == kNullType);
  257. r.GetNull();
  258. cout << key << endl;
  259. continue;
  260. }
  261. else if (0 == strcmp(key, "pi")) {
  262. RAPIDJSON_ASSERT(r.PeekType() == kNumberType);
  263. cout << key << ":" << r.GetDouble() << endl;
  264. continue;
  265. }
  266. else if (0 == strcmp(key, "a")) {
  267. RAPIDJSON_ASSERT(r.PeekType() == kArrayType);
  268. r.EnterArray();
  269. cout << key << ":[ ";
  270. while (r.NextArrayValue()) {
  271. if (r.PeekType() == kNumberType) {
  272. cout << r.GetDouble() << " ";
  273. }
  274. else if (r.PeekType() == kStringType) {
  275. cout << r.GetString() << " ";
  276. }
  277. else {
  278. r.SkipArray();
  279. break;
  280. }
  281. }
  282. cout << "]" << endl;
  283. }
  284. else {
  285. cout << key << ":skipped" << endl;
  286. r.SkipValue();
  287. }
  288. }
  289. return 0;
  290. }
  291. RAPIDJSON_DIAG_POP