Jansson (a C library for JSON data) 使用教學#
Prerequisite#
了解什麼是JSON,可參考連結
從官方的github repository下載原始檔案。
Tip
我個人是使用v2.14
參考官方的安裝方式
Tip
我個人是使用Ubuntu 22.04做為開發環境,依照我的使用經驗來說使用CMake安裝比較不會出問題,至於要要不要使用shared library可以按個人喜好決定。
在
source file裡面include<jansson.h>即可使用編譯時要記得加上
-ljansson來link library
Tip
建議還是要理解編譯時如何link第3方的library,若不清楚的話可以參考連結
使用教學#
接下來的內容都可以從官網的API Reference找到,主要是希望按照個人認為的重要順序去重新編排順序,並且將內容濃縮。
基本觀念 & 操作#
Type system#
Data type |
json type |
c type |
description |
|---|---|---|---|
|
|
X |
singleton |
|
|
X |
singleton |
|
|
X |
singleton |
|
|
char* |
JSON strings are mapped to C-style null-terminated character arrays, and UTF-8 encoding is used internally. |
|
|
|
|
|
|
|
|
|
|
X |
|
|
|
X |
The key is a Unicode string and the value is any JSON value. |
所有種類的json object都使用
json_t作為在c語言程式裡的type所有關於json object的操作都必須透過
pointer來間接操作。可以使用function
json_is_XXX(json_t*)來檢查json_t實際到底是不是某種type。
例如:檢查是否為integer可以使用functionjson_is_integer(ptr)最簡單的產生物件方式之一是直接使用function
json_XXX(value)去產生
例如:使用json_real(1.0)產生一個內容值為1.0的real物件除了
singleton的3種type之外的非containertype都可以使用json_XXX_set(ptr, value) / json_XXX_value(ptr)分別去更改 / 取得json object的值
例如:使用json_real_set(ptr, 3.0) / double d = json_real_value(ptr)去更改 / 取得ptr 的值
Note
用 json_string_value 取出來的值是 const char * 且不能自己去執行 free ,必須交由library管理
所有對
array的操作都是json_array_XXX。XXX為常見的對array的動作,例如:size、set、get、insert、append、del、clear等等。所有對
map的操作都是json_object_XXX。XXX為常見的對map的動作,例如:size、set、get、update、append、del、clear等等。針對
array與map,library有提供 macrojson_XXX_foreach(ptr, ...)來執行loop
Reference Count#
jansson會半自動管理json object的記憶體使用,其管理方式為對於json object 增加一個 refcount 來做管理。 refcount 在json object被配置記憶體時會被設定為 1 。一旦json object的 refcount 變成 0 的瞬間,該json object所佔用的記憶體空間會被釋放。Programmer必須自己管理 refcount 。
Note
若 container 的 refcount 歸零的時候,其所有 content 的 refcount 也會被減 1 。若 content 的 refcount 因此 歸零的話則該物件也會消失。這個過程可以連鎖反應。
refcount 只有2種狀況會受影響
使用非
steal版本的function將json object裝入其它array或map時使用
json_t *json_incref(json_t *json)或者void json_decref(json_t *json)直接操作。
Thread-safty#
jansson library不保證 object content 是thread-safe。但只要compiler支援便會保證 refcount 是thread-safe的。可以通過preprocessor constant JANSSON_THREAD_SAFE_REFCOUNT 是否有定義去檢查。
Steal function#
用來增加 container 內容的function多數都有對應的 steal function ,其名稱為 json_XXX_XXX_new()。Steal function 的作用與其對應的普通function一樣,唯一的差別是不會去增加 refcount 。
jansson會提供steal function是因為下面這個關於 container 的使用場景非常常見
1{
2 ...
3
4 json_t *arr = json_array();
5 json_t *i = json_integer(0);
6 json_array_append(arr, i);
7 json_decref(i);
8
9 ...
10
11 return;
12}
在這個使用場景之下, i 這個pointer只是單純用來新增一個物件,之後要將這個物件統一由 conainer 管理,但因為 json_array_append 會增加 refcount 所以在這個使用場景之下必須使用 json_decref 去主動管理 refcount 。通過steal function的提供,上面的範例可以更改成
1{
2 ...
3
4 json_t *arr = json_array();
5 json_t *i = json_integer(0);
6 json_array_append_new(arr, i);
7
8 ...
9
10 return;
11}
Object Parsing#
json的本質就是一個 notation,因此 json object 可以與 string 之間天生就可以互相轉換。 將 json object 轉換成 string 的過程稱之為 Encoding ,而反過來將 string 轉換成 json object 的過程稱之為 Decoding 。
Flag#
Encoding 與 Decoding 都有一些關於 string format的 flag 可以去控制 Encoding 與 Decoding 之間的轉換。 flag 的預設值為 0 。 比較常用的 flag 為 Encoding 的 JSON_INDENT(n)。 其他的 flag 可以參考官方Encoding以及Decoding的API文件。
Encoding#
Encoding 提供的function主要的差異是輸出的載體做區分。
輸出
char * 字串的json_dumps(字串要自行free)輸出到
buffer的json_dumpb輸出到
file的json_dumpf輸出到
stream output的json_dumpfd輸出到
指定路徑的json_dump_file
Decoding#
Error reporting#
有很多原因可能會造成jansson發生錯誤,但最常見的原因是 json string 的格式不正確。jansson 處理 error 的方式是將所有與 error 相關的資訊都封裝在一個 json_error_t 變數裡。 若在 Decoding 時有把 json_error_t 的 address 作為參數傳入,則當發生錯誤時對應的錯誤資訊都會被自動紀錄到該變數。接著再針對錯誤做後續處理即可。若不想處理錯誤訊息的話提供 NULL 即可。 json_error_t 的詳細內容可以參考官網的API 文件。
Decoding function#
Decoding 提供的function與 Encoding 有對應關係。
輸入
char * 字串的json_loads從
buffer輸入的json_loadb從
file輸入的json_loadf從
stream input輸入的json_loadfd從
指定路徑的檔案輸入的json_load_file
Decoding by format string#
jansson提供了3個通過 formatted string 來做 Decoding 的function。 分別是 json_pack 、 json_pack_ex 、 json_vpack_ex 。這3個function的主要功能有點類似 printf 的使用方式。提供含有 format specifier 的string以及對應的值作為參數即可得到完整的 json object (若formatted string代表的是有內容的 container 的話會連內容都一併配置好)。 而他們之間的差異主要是在於 Decoding 細節控制 、 error 處理 、 呼叫方式 等方面。 關於細節以及 format specifier 可以參考官網API 文件。
Equality#
要比較兩個 json object 要使用 json_equal 這個function。 若是 container 類型的 json object ,則要所有內容都相等才會得到 true 。其他類型的 json object 則是很單純的先比對 type 後比對 value 。
Copying#
copy function 主要的功能是複製一個擁有相同的 value 的 json object 。但複製出來的 json object 會有自己全新的 refCount 。
jansson提供了兩個 copy function : json_copy 與 json_deep_copy 。 這兩個function的差別在於若複製的 json object 是 container 的話內容物是否要另外複製。若是使用在普通的 json object 上其作用沒有差異。