JSON解析
- JSONCPP
- C++实现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解析器
#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
#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,2e10LITERAL_TRUE, ///< trueLITERAL_FALSE,///< falseLITERAL_NULL, ///< nullBEGIN_ARRAY, ///< [ 数组左括号END_ARRAY, ///< ] 数组右括号END_OF_SOURCE, ///< EOFERROR };JsonTokenType Scan(); // 扫描下一个,返回下一个token的typevoid 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 sourcesize_t current_; ///< current pos of processing charactersize_t prev_pos_; ///< previous handling pos;float value_number_; ///< number valuestd::string value_string_; ///< string value};// end of class Scanner} // namespace json} // namespace Cliu
#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() { // 判断是否是trueif (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 partif (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:// errorstd::string message = "Unsupported Token: ";message += c;Error(std::string(message));return JsonTokenType::ERROR;}return JsonTokenType();
}} // namespace json} // namespace Cliu
#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
#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