zjson
介紹
從node.js轉到c++,特別懷念在js中使用json那種暢快感。在c++中也使用過了些庫,但提供的介面使用方式,總不是習慣,很煩鎖,介面函式太多,不直觀。參考了很多庫,如:rapidjson, cJson, CJsonObject, drleq-cppjson, json11等,受cJson的資料結構啟發很大,決定用C++手擼一個。最後因為資料儲存需要不區分型別,又要能知道其型別,所以選擇了C++17才支援的std::variant以及std::any,最終,C++版本定格在c++17,本庫設計為單標頭檔案,且不依賴c++標準庫以外的任何庫。
專案名稱說明
本人姓名拼音第一個字母z加上josn,即得本專案名稱zjson,沒有其它任何意義。我將編寫一系列以z開頭的相關專案,命名是個很麻煩的事,因此採用了這種簡單粗暴的方式。
設計思路
簡單的介面函式、簡單的使用方法、靈活的資料結構、儘量支援鏈式操作。使用模板技術,使用給Json物件增加值的方法只有兩個,AddValueBase和AddValueJson。採用連結串列結構(向cJSON致敬)來儲存Json物件,請看我下面的資料結構設計,表頭與後面的結點,都用使用一致的結構,這使得在索引操作([])時,可以進行鏈式操作。
專案進度
專案目前完成一半,可以新建Json物件,增加資料,按key(Object型別)或索引(Array型別)提取相應的值或子物件,生成json字串。
已經做過記憶體洩漏測試,解構函式能正確執行,百萬級別生成與銷燬未見記憶體明顯增長。
任務列表:
- [x] 建構函式、複製建構函式、解構函式
- [x] AddValueBase(為Json物件增加值型別)、AddValueJson(為Json物件增加物件型別)
- [x] operator=、operator[]
- [x] toString(生成json字串)
- [x] toInt、toDouble、toFalse 等值型別轉換
- [x] isError、isNull、isArray 等節點型別判斷
- [ ] parse, 從json字串生成Json物件;相應的建構函式
- [ ] Extend Json - 擴充套件物件
- [ ] Remove[All] key - 刪除資料, 因為Json物件允許重複的key
- [ ] findAll - 查詢全部, 因為Json物件允許重複的key
- [ ] std::move語義
資料結構
Json 節點型別定義
(內部使用,資料型別只在Json類內部使用)
enum Type {
Error, //錯誤,查詢無果,這是一個無效Json物件
False, //Json值型別 - false
True, //Json值型別 - true
Null, //Json值型別 - null
Number, //Json值型別 - 數字,庫中以double型別儲存
String, //Json值型別 - 字串
Object, //Json類物件型別 - 這是Object巢狀,物件型中只有child需要關注
Array //Json類物件型別 - 這是Array巢狀,物件型中只有child需要關注
};
Json 節點定義
class Json {
Json* brother; //與cJSON中的next對應,值型別才有效,指向並列的資料,但有可能是值型別,也有可能是物件型別
Json* child; //孩子節點,物件型別才有效
Type type; //節點型別
std::variant <int, bool, double, string> data; //節點資料
string name; //節點的key
}
介面說明
公開的物件型別,json只支援Object與Array兩種物件,與內部型別對應(公開型別)。
enum class JsonType
{
Object = 6,
Array = 7
};
介面列表
- Json(JsonType type = JsonType::Object) //預設建構函式,生成Object或Array型別的Json物件
- Json(const Json& origin) //複製建構函式
- Json& operator = (const Json& origin) //賦值操作
- Json operator[](const int& index) //Json陣列物件元素查詢
- Json operator[](const string& key) //Json Object 物件按key查詢
- bool AddValueJson(Json& obj) //增加子Json類物件型別, 只面向Array
- bool AddValueJson(string name, Json& obj) //增加子Json類物件型別,當obj為Array時,name會被忽略
- template<typename T> bool AddValueBase(T value) //增加值物件型別,只面向Array
- template<typename T> bool AddValueBase(string name, T value) //增加值物件型別,當this為Array時,name會被忽略
- string toString() //Json物件序列化為字串
- bool isError() //無效Json物件判定
- bool isNull() //null值判定
- bool isObject() //Object物件判定
- bool isArray() //Array物件判定
- bool isNumber() //number值判定,Json內使用double型別儲存number值
- bool isTrue() //true值判定
- bool isFalse() //false值判定
- int toInt() //值物件轉為int
- float toFloat() //值物件轉為float
- double toDouble() //值物件轉為double
- bool toBool() //值物件轉為bool
程式設計示例
簡單使用示例
Json ajson(JsonType::Object); //新建Object物件,輸入引數可以省略
std::string data = "kevin";
ajson.AddValueBase("fail", false); //增加false值物件
ajson.AddValueBase("name", data); //增加字串值物件
ajson.AddValueBase("school-en", "the 85th.");
ajson.AddValueBase("age", 10); //增加number值物件,此處為整數
ajson.AddValueBase("scores", 95.98); //增加number值物件,此處為浮點數,還支援long,long long
ajson.AddValueBase("nullkey", nullptr); //增加null值物件,需要送入nullptr, NULL會被認為是整數0
Json sub; //新建Object物件
sub.AddValueBase("math", 99);
ajson.AddValueJson("subJson", sub); //為ajson增加子Json型別物件,完成巢狀需要
Json subArray(JsonType::Array); //新建Array物件,輸入引數不可省略
subArray.AddValueBase("I'm the first one."); //增加Array物件的字串值子物件
subArray.AddValueBase("two", 2); //增加Array物件的number值子物件,第一個引數會被忽略
Json sub2;
sub2.AddValueBase("sb2", 222);
subArray.AddValueJson("subObj", sub2); //為Array物件增加Object類子物件,完成巢狀需求
ajson.AddValueJson("array", subArray); //為ajson增加Array物件,且這個Array物件本身就是一個巢狀結構
std::cout << "ajson's string is : " << ajson.toString() << std::endl; //輸出ajson物件序列化後的字串, 結果見下方
string name = ajson["name"].toString(); //提取key為name的字串值,結果為:kevin
int oper = ajson["sb2"].toInt(); //提取巢狀深層結構中的key為sb2的整數值,結果為:222
Json operArr = ajson["array"]; //提取key為array的陣列物件
string first = ajson["array"][0].toString(); //提取key為array的陣列物件的序號為0的值,結果為:I'm the first one.
ajson序列化後結果為:
{
"fail": false,
"name": "kevin",
"school-en": "the 85th.",
"age": 10,
"scores": 95.98,
"nullkey": null,
"subJson": {
"math": 99
},
"array": [
"I'm the first one.",
2,
{
"sb2": 222
}
]
}
詳情請參看demo.cpp或tests目錄下的測試用例
專案地址
https://gitee.com/zhoutk/zjson
或
https://github.com/zhoutk/zjson
執行方法
該專案在vs2019, gcc7.5, clang12.0下均編譯執行正常。
git clone https://github.com/zhoutk/zjson
cd zjson
cmake -Bbuild .
---windows
cd build && cmake --build .
---linux & mac
cd build && make
run zjson or ctest
相關專案
會有一系列專案出爐,網路服務相關,敬請期待...