lookaheadparser.cpp 9.2 KB

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