messagereader.cpp 2.75 KB
Newer Older
Milo Yip's avatar
Milo Yip committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// Reading a message JSON with Reader (SAX-style API).
// The JSON should be an object with key-string pairs.

#include "rapidjson/reader.h"
#include "rapidjson/error/en.h"
#include <iostream>
#include <string>
#include <map>

using namespace std;
using namespace rapidjson;

typedef map<string, string> MessageMap;

15 16 17 18 19
#if defined(__GNUC__)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif

20 21 22 23 24
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(switch-enum)
#endif

25 26
struct MessageHandler
    : public BaseReaderHandler<UTF8<>, MessageHandler> {
27
    MessageHandler() : messages_(), state_(kExpectObjectStart), name_() {}
Milo Yip's avatar
Milo Yip committed
28 29

    bool StartObject() {
30 31 32 33
        switch (state_) {
        case kExpectObjectStart:
            state_ = kExpectNameOrObjectEnd;
            return true;
34
        default:
35 36
            return false;
        }
Milo Yip's avatar
Milo Yip committed
37 38 39
    }

    bool String(const char* str, SizeType length, bool) {
40 41
        switch (state_) {
        case kExpectNameOrObjectEnd:
Milo Yip's avatar
Milo Yip committed
42
            name_ = string(str, length);
43 44 45 46 47 48
            state_ = kExpectValue;
            return true;
        case kExpectValue:
            messages_.insert(MessageMap::value_type(name_, string(str, length)));
            state_ = kExpectNameOrObjectEnd;
            return true;
49 50
        default:
            return false;
51
        }
Milo Yip's avatar
Milo Yip committed
52 53 54 55
    }

    bool EndObject(SizeType) { return state_ == kExpectNameOrObjectEnd; }

56
    bool Default() { return false; } // All other events are invalid.
Milo Yip's avatar
Milo Yip committed
57

58
    MessageMap messages_;
Milo Yip's avatar
Milo Yip committed
59 60 61
    enum State {
        kExpectObjectStart,
        kExpectNameOrObjectEnd,
62
        kExpectValue
Milo Yip's avatar
Milo Yip committed
63 64 65 66
    }state_;
    std::string name_;
};

67 68 69 70
#if defined(__GNUC__)
RAPIDJSON_DIAG_POP
#endif

71 72 73 74
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif

Milo Yip's avatar
Milo Yip committed
75
static void ParseMessages(const char* json, MessageMap& messages) {
Milo Yip's avatar
Milo Yip committed
76 77 78
    Reader reader;
    MessageHandler handler;
    StringStream ss(json);
79 80 81 82 83 84 85 86
    if (reader.Parse(ss, handler))
        messages.swap(handler.messages_);   // Only change it if success.
    else {
        ParseErrorCode e = reader.GetParseErrorCode();
        size_t o = reader.GetErrorOffset();
        cout << "Error: " << GetParseError_En(e) << endl;;
        cout << " at offset " << o << " near '" << string(json).substr(o, 10) << "...'" << endl;
    }
Milo Yip's avatar
Milo Yip committed
87 88 89 90 91
}

int main() {
    MessageMap messages;

92 93
    const char* json1 = "{ \"greeting\" : \"Hello!\", \"farewell\" : \"bye-bye!\" }";
    cout << json1 << endl;
Milo Yip's avatar
Milo Yip committed
94 95 96 97 98
    ParseMessages(json1, messages);

    for (MessageMap::const_iterator itr = messages.begin(); itr != messages.end(); ++itr)
        cout << itr->first << ": " << itr->second << endl;

99 100 101 102
    cout << endl << "Parse a JSON with invalid schema." << endl;
    const char* json2 = "{ \"greeting\" : \"Hello!\", \"farewell\" : \"bye-bye!\", \"foo\" : {} }";
    cout << json2 << endl;
    ParseMessages(json2, messages);
Milo Yip's avatar
Milo Yip committed
103 104 105

    return 0;
}