C++ JSON解析

C++ JSON解析

JSONCPP

JSONCPP源码链接:https://github.com/open-source-parsers/jsoncpp

  1. JSOCPP源码下载以后,首先复制一份include文件夹下的json文件夹,头文件留着后续备用。
    在这里插入图片描述
  2. 使用Cmake生成项目。在IDE中编译jsoncpp_lib,可以在项目的lib/Debug文件夹下找到jsoncpp.lib,在bin/Debug/文件夹下找到jsoncpp.dll。将头文件和动态链接库文件,放入项目中即可使用。
    在这里插入图片描述
    在这里插入图片描述
    jsoncpp库中的类被定义到了一个Json命名空间中,使用时最好先声明这个命名空间。

使用jsoncpp库解析json格式的数据,三个类:

  • Value 类:将json支持的数据类型进行了包装,最终得到一个Value类型。
  • FastWriter类:将Value对象中的数据序列化为字符串。
  • Reader类:反序列化,将json字符串解析成Value类型。

C++实现JSON解析器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
#pragma once
#include<string>
#include<map>
#include<vector>
#include<sstream>
#include<iostream>

namespace Cliu {

namespace json {
class JsonElement;
using JsonObject = std::map<std::string, JsonElement*>;
using JsonArray = std::vector<JsonElement*>;

class JsonElement {
public:
enum class Type {
JSON_OBJECT,
JSON_ARRAY,

JSON_STRING,
JSON_NUMBER,

JSON_BOOL,

JSON_NULL
};

union Value {
JsonObject* value_object;
JsonArray* value_array;

std::string* value_string;
float value_number;

bool value_bool;
};

JsonElement() : JsonElement(Type::JSON_NULL) {}

JsonElement(const Type& type) : type_(type) {
switch (type) {
case Type::JSON_OBJECT:
value_.value_object = new std::map<std::string, JsonElement*>();
break;
case Type::JSON_ARRAY:
value_.value_array = new std::vector<JsonElement*>();
break;
case Type::JSON_STRING:
value_.value_string = new std::string("");
break;
case Type::JSON_NUMBER:
value_.value_number = 0;
break;
case Type::JSON_BOOL:
value_.value_bool = false;
break;
case Type::JSON_NULL:
break;
default:
break;
}
};

JsonElement(JsonObject* object) : type_(Type::JSON_OBJECT) { value(object); }
JsonElement(JsonArray* array) : type_(Type::JSON_ARRAY) { value(array); }
JsonElement(std::string* str) : type_(Type::JSON_STRING) { value(str); }
JsonElement(float number) : type_(Type::JSON_NUMBER) { value(number); }
JsonElement(bool val) : type_(Type::JSON_BOOL) { value(val); }

~JsonElement() {
if (type_ == Type::JSON_OBJECT) {
JsonObject* object = value_.value_object;
for (auto& a : *object) {
delete a.second;
}
delete object;
}
else if (type_ == Type::JSON_ARRAY) {
JsonArray* array = value_.value_array;
for (auto& item : *array) {
delete item;
}
delete array;
}
else if (type_ == Type::JSON_STRING) {
std::string* val = value_.value_string;
delete val;
}
}

Type type() { return type_; }

void value(JsonObject* value) {
type_ = Type::JSON_OBJECT;
value_.value_object = value;
}
void value(JsonArray* value) {
type_ = Type::JSON_ARRAY;
value_.value_array = value;
}
void value(std::string* value) {
type_ = Type::JSON_STRING;
value_.value_string = value;
}
void value(float value) {
type_ = Type::JSON_NUMBER;
value_.value_number = value;
}
void value(bool value) {
type_ = Type::JSON_BOOL;
value_.value_bool = value;
}

JsonObject* AsObject() {
if (type_ == Type::JSON_OBJECT) {
return value_.value_object;
}
else {
Error("Type of JsonElement isn't JsonObject!");
return nullptr;
}
}

JsonArray* AsArray() {
if (type_ == Type::JSON_ARRAY) {
return value_.value_array;
}
else {
Error("Type of JsonElement isn't JsonArray!");
return nullptr;
}
}

std::string* AsString() {
if (type_ == Type::JSON_STRING) {
return value_.value_string;
}
else {
Error("Type of JsonElement isn't String!");
return nullptr;
}
}

float AsNumber() {
if (type_ == Type::JSON_NUMBER) {
return value_.value_number;
}
else {
Error("Type of JsonElement isn't Number!");
return 0.0f;
}
}

bool AsBoolean() {
if (type_ == Type::JSON_BOOL) {
return value_.value_bool;
}
else {
Error("Type of JsonElement isn't Boolean!");
return false;
}
}

std::string Dumps() {
std::stringstream ss;
switch (type_) {
case Type::JSON_OBJECT:
ss << *(value_.value_object);
break;
case Type::JSON_ARRAY:
ss << *(value_.value_array);
break;
case Type::JSON_STRING:
ss << '\"' << *(value_.value_string) << '\"';
break;
case Type::JSON_NUMBER:
ss << value_.value_number;
break;
case Type::JSON_BOOL:
ss << (value_.value_bool == true ? "true" : "false");
break;
case Type::JSON_NULL:
ss << "null";
break;
default:
break;
}
return ss.str();
}

friend std::ostream& operator<<(std::ostream& os, const JsonObject& object) {
os << "{";
for (auto iter = object.begin(); iter != object.end(); iter++) {
os << '\"' << iter->first << '\"' << ": " << iter->second->Dumps();
if (iter != --object.end()) {
os << ", ";
}
}
os << "}";
return os;
}

friend std::ostream& operator<<(std::ostream& os, const JsonArray& array) {
os << "[";
for (size_t i = 0; i < array.size(); i++) {
os << array[i]->Dumps();
if (i != array.size() - 1) {
os << ", ";
}
}
os << "]";
return os;
}

private:
Type type_;
Value value_;
};

} // namespace json

} // namespace Cliu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#pragma once
#include<string>
#include"Error.h"
#include<iostream>

namespace Cliu {

namespace json {

class Scanner {
public:
Scanner(const std::string& source) : source_(source), current_(0) {}

Scanner(std::string&& source) : source_(std::move(source)), current_(0) {}
enum class JsonTokenType
{
BEGIN_OBJECT, ///< {
END_OBJECT, ///< }

VALUE_SEPARATOR, ///< , 逗号
NAME_SEPARATOR, ///< : 冒号

VALUE_STRING, ///< "string"
VALUE_NUMBER, ///< 1,2,2e10

LITERAL_TRUE, ///< true
LITERAL_FALSE,///< false
LITERAL_NULL, ///< null

BEGIN_ARRAY, ///< [ 数组左括号
END_ARRAY, ///< ] 数组右括号

END_OF_SOURCE, ///< EOF

ERROR

};

JsonTokenType Scan(); // 扫描下一个,返回下一个token的type

void Rollback();

friend std::ostream& operator<<(std::ostream& os, const JsonTokenType& type) {
switch (type) {
case JsonTokenType::BEGIN_ARRAY:
os << "[";
break;
case JsonTokenType::END_ARRAY:
os << "]";
break;
case JsonTokenType::BEGIN_OBJECT:
os << "{";
break;
case JsonTokenType::END_OBJECT:
os << "}";
break;
case JsonTokenType::NAME_SEPARATOR:
os << ":";
break;
case JsonTokenType::VALUE_SEPARATOR:
os << ",";
break;
case JsonTokenType::VALUE_NUMBER:
os << "number";
break;
case JsonTokenType::VALUE_STRING:
os << "string";
break;
case JsonTokenType::LITERAL_TRUE:
os << "true";
break;
case JsonTokenType::LITERAL_FALSE:
os << "false";
break;
case JsonTokenType::LITERAL_NULL:
os << "null";
break;
case JsonTokenType::END_OF_SOURCE:
os << "EOF";
break;
default:
break;
}
return os;
}

float GetNumberValue() { return value_number_; };

const std::string& GetStringValue() { return value_string_; };

private:
bool IsAtEnd();
char Advance();
void ScanTrue();
void ScanFalse();
void ScanNull();
void ScanString();
void ScanNumber();

char Peek();
char PeekNext();
bool IsDigit(char c);


private:
std::string source_; ///< json source
size_t current_; ///< current pos of processing character
size_t prev_pos_; ///< previous handling pos;

float value_number_; ///< number value
std::string value_string_; ///< string value

};// end of class Scanner

} // namespace json

} // namespace Cliu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include "Scanner.h"

namespace Cliu {

namespace json {

bool Scanner::IsAtEnd() {
return current_ >= source_.size();
}

char Scanner::Advance() {
return source_[current_++];
}

void Scanner::Rollback() { current_ = prev_pos_; }

bool Scanner::IsDigit(char c) { return c >= '0' && c <= '9'; }

char Scanner::Peek() { // 获取下一个
if (IsAtEnd()) return '\0';
return source_[current_];
}

char Scanner::PeekNext() { // 要确保下一个值是存在的
if (current_ + 1 >= source_.size()) return '\0';
return source_[current_ + 1];
}

void Scanner::ScanTrue() { // 判断是否是true
if (source_.compare(current_, 3, "rue") == 0) {
current_ += 3;
}
else {
Error("Scan `true` error");
}
}

void Scanner::ScanFalse() {
if (source_.compare(current_, 4, "alse") == 0) {
current_ += 4;
}
else {
Error("Scan `false` error");
}
}

void Scanner::ScanNull() {
if (source_.compare(current_, 3, "ull") == 0) {
current_ += 3;
}
else {
Error("Scan `null` error");
}
}

void Scanner::ScanString() {
size_t pos = current_;
while (Peek() != '\"' && !IsAtEnd()) {
Advance();// 再走一步 //没有考虑转义字符
}
if (IsAtEnd()) {
Error("invalid string: missing closing quote");
}
Advance();

value_string_ = source_.substr(pos, current_ - pos - 1);
}

void Scanner::ScanNumber() {
size_t pos = current_ - 1;

while (IsDigit(Peek())) {
Advance();
}

// fractional part
if (Peek() == '.' && IsDigit(PeekNext())) {
Advance();
while (IsDigit(Peek())) {
Advance();
}
}

value_number_ = std::atof(source_.substr(pos, current_ - pos).c_str());
}


Scanner::JsonTokenType Scanner::Scan()
{
// 判断是否扫描完毕
if (IsAtEnd()) {
return JsonTokenType::END_OF_SOURCE; // 返回扫描完毕标识符
}
prev_pos_ = current_;
char c = Advance(); // 获取下一个字符
switch (c)
{
case '[':
return JsonTokenType::BEGIN_ARRAY;
case ']':
return JsonTokenType::END_ARRAY;
case '{':
return JsonTokenType::BEGIN_OBJECT;
case '}':
return JsonTokenType::END_OBJECT;
case ':':
return JsonTokenType::NAME_SEPARATOR;
case ',':
return JsonTokenType::VALUE_SEPARATOR;
case 't':
ScanTrue();
return JsonTokenType::LITERAL_TRUE;
case 'f':
ScanFalse();
return JsonTokenType::LITERAL_FALSE;
case 'n':
ScanNull();
return JsonTokenType::LITERAL_NULL;
case '-':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
ScanNumber();
return JsonTokenType::VALUE_NUMBER;
case '\"':
ScanString();
return JsonTokenType::VALUE_STRING;
case ' ':
case '\r':
case '\n':
case '\t':
return Scan();
default:
// error
std::string message = "Unsupported Token: ";
message += c;
Error(std::string(message));
return JsonTokenType::ERROR;

}
return JsonTokenType();
}

} // namespace json

} // namespace Cliu



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#pragma once
#include"Scanner.h"
#include"JsonElement.h"

namespace Cliu {

namespace json {

class Parser {
using JsonTokenType = Scanner::JsonTokenType;

public:
JsonElement* Parse();
Parser(const Scanner& scanner) : scanner_(scanner) {}

private:
JsonObject* ParseObject();
JsonArray* ParseArray();

private:
Scanner scanner_;
};

} // namespace json

} // namespace Cliu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include"Parser.h"

namespace Cliu {

namespace json {

JsonElement* Parser::Parse() {
JsonElement* element = new JsonElement();
JsonTokenType token_type_ = scanner_.Scan();

if (token_type_ != JsonTokenType::END_OF_SOURCE) {
switch (token_type_) {
case JsonTokenType::BEGIN_OBJECT: {
JsonObject* object = ParseObject();
element->value(object);
break;
}
case JsonTokenType::BEGIN_ARRAY: {
JsonArray* array = ParseArray();
element->value(array);
break;
}
case JsonTokenType::VALUE_STRING: {
std::string* val = new std::string(scanner_.GetStringValue());
element->value(val);
break;
}
case JsonTokenType::VALUE_NUMBER: {
element->value(scanner_.GetNumberValue());
break;
}
case JsonTokenType::LITERAL_TRUE: {
element->value(true);
break;
}
case JsonTokenType::LITERAL_FALSE: {
element->value(false);
break;
}
case JsonTokenType::LITERAL_NULL: {
break;
}
default:
break;
}
}
return element;
}

JsonObject* Parser::ParseObject() {
JsonObject* res = new JsonObject();

JsonTokenType next = scanner_.Scan();
if (next == JsonTokenType::END_OBJECT) { //判断是否为空对象
return res;
}
scanner_.Rollback();// 回退一步

while (true) {
next = scanner_.Scan();
if (next != JsonTokenType::VALUE_STRING) {
Error("Key must be string!");
}
std::string key = scanner_.GetStringValue();
next = scanner_.Scan();
if (next != JsonTokenType::NAME_SEPARATOR) {
Error("Expected ':' in object!");
}
(*res)[key] = Parse();
next = scanner_.Scan();
if (next == JsonTokenType::END_OBJECT) {
break;
}
if (next != JsonTokenType::VALUE_SEPARATOR) {
Error("Expected ',' in object!");
}
}

return res;
}

JsonArray* Parser::ParseArray() {
JsonArray* res = new JsonArray();
JsonTokenType next = scanner_.Scan();
if (next == JsonTokenType::END_ARRAY) {
return res;
}
scanner_.Rollback();

while (true) {
res->push_back(Parse());
next = scanner_.Scan();
if (next == JsonTokenType::END_ARRAY) {
break;
}
if (next != JsonTokenType::VALUE_SEPARATOR) {
Error("Expected ',' in array!");
}
}

return res;
}


} // namespace json

} // namespace Cliu

参考列表
https://subingwen.cn/cpp/jsoncpp/?highlight=json
https://blog.csdn.net/qq_43142808/article/details/115654942
https://zhuanlan.zhihu.com/p/476271291


C++ JSON解析
https://cauccliu.github.io/2024/03/26/C++ JSON解析/
Author
Liuchang
Posted on
March 26, 2024
Licensed under