JSON解析
JSONCPP
JSONCPP源码链接:https://github.com/open-source-parsers/jsoncpp
- JSOCPP源码下载以后,首先复制一份include文件夹下的json文件夹,头文件留着后续备用。
- 使用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解析器
cpp
#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
cpp
#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
cpp
#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
cpp
#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
cpp
#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