1// Reading a message JSON with Reader (SAX-style API).
2// The JSON should be an object with key-string pairs.
3
4#include "rapidjson/reader.h"
5#include "rapidjson/error/en.h"
6#include <iostream>
7#include <string>
8#include <map>
9
10using namespace std;
11using namespace rapidjson;
12
13typedef map<string, string> MessageMap;
14
15#if defined(__GNUC__)
16RAPIDJSON_DIAG_PUSH
17RAPIDJSON_DIAG_OFF(effc++)
18#endif
19
20struct MessageHandler
21    : public BaseReaderHandler<UTF8<>, MessageHandler> {
22    MessageHandler() : messages_(), state_(kExpectObjectStart), name_() {}
23
24    bool StartObject() {
25        switch (state_) {
26        case kExpectObjectStart:
27            state_ = kExpectNameOrObjectEnd;
28            return true;
29        default:
30            return false;
31        }
32    }
33
34    bool String(const char* str, SizeType length, bool) {
35        switch (state_) {
36        case kExpectNameOrObjectEnd:
37            name_ = string(str, length);
38            state_ = kExpectValue;
39            return true;
40        case kExpectValue:
41            messages_.insert(MessageMap::value_type(name_, string(str, length)));
42            state_ = kExpectNameOrObjectEnd;
43            return true;
44        default:
45            return false;
46        }
47    }
48
49    bool EndObject(SizeType) { return state_ == kExpectNameOrObjectEnd; }
50
51    bool Default() { return false; } // All other events are invalid.
52
53    MessageMap messages_;
54    enum State {
55        kExpectObjectStart,
56        kExpectNameOrObjectEnd,
57        kExpectValue
58    }state_;
59    std::string name_;
60};
61
62#if defined(__GNUC__)
63RAPIDJSON_DIAG_POP
64#endif
65
66void ParseMessages(const char* json, MessageMap& messages) {
67    Reader reader;
68    MessageHandler handler;
69    StringStream ss(json);
70    if (reader.Parse(ss, handler))
71        messages.swap(handler.messages_);   // Only change it if success.
72    else {
73        ParseErrorCode e = reader.GetParseErrorCode();
74        size_t o = reader.GetErrorOffset();
75        cout << "Error: " << GetParseError_En(e) << endl;;
76        cout << " at offset " << o << " near '" << string(json).substr(o, 10) << "...'" << endl;
77    }
78}
79
80int main() {
81    MessageMap messages;
82
83    const char* json1 = "{ \"greeting\" : \"Hello!\", \"farewell\" : \"bye-bye!\" }";
84    cout << json1 << endl;
85    ParseMessages(json1, messages);
86
87    for (MessageMap::const_iterator itr = messages.begin(); itr != messages.end(); ++itr)
88        cout << itr->first << ": " << itr->second << endl;
89
90    cout << endl << "Parse a JSON with invalid schema." << endl;
91    const char* json2 = "{ \"greeting\" : \"Hello!\", \"farewell\" : \"bye-bye!\", \"foo\" : {} }";
92    cout << json2 << endl;
93    ParseMessages(json2, messages);
94
95    return 0;
96}
97