jansson の使い方

# jansson の使い方

## jansson とは?

C言語で利用可能な json の読み書きができるライブラリです。MIT ライセンスです。

Web サイト
https://digip.org/jansson/

ソースコード
https://github.com/akheron/jansson

最新のドキュメント
https://jansson.readthedocs.io/en/latest/

## インストール方法

### ubuntu の場合

```bash
sudo apt-get install -y libjansson-dev
```

## jansson を使用したアプリのビルド方法

1. cmake (window および unix 系)
2. autotools (unix 系のみ)

## 基本的な概念


### [json_t](https://jansson.readthedocs.io/en/latest/apiref.html?#c.json_t) [ソースコードでの定義](https://github.com/akheron/jansson/blob/0dffb4284e7872c6e26956ad85fe127ba77220dc/src/jansson.h#L61-L64)

* JSONの値を保持するためのデータ構造です。
* データは参照カウンタによってメモリ管理されます。
* [json_t](https://jansson.readthedocs.io/en/latest/apiref.html?#c.json_t) は常にポインタでデータを参照します。
* JSONのどのタイプのデータを管理しているか、タイプ情報を保持しています。(enum の [json_type](https://jansson.readthedocs.io/en/latest/apiref.html?#c.json_type) で表されます。)

### 参照カウンタ

* [json_incref](https://jansson.readthedocs.io/en/latest/apiref.html?#c.json_incref) でインクリメントします。
* [json_decref](https://jansson.readthedocs.io/en/latest/apiref.html?#c.json_decref) でデクリメントします。
* 新しい [json_t](https://jansson.readthedocs.io/en/latest/apiref.html?#c.json_t)オブジェクトを作成したときは参照カウンタは 1 となります。
* [json_decref](https://jansson.readthedocs.io/en/latest/apiref.html?#c.json_decref) でデクリメントして参照カウンタが 0 になれば [json_t](https://jansson.readthedocs.io/en/latest/apiref.html?#c.json_t)オブジェクトに確保されたメモリが解放されます。
* 逆に参照カウンタのデクリメントを忘れるとメモリリークが発生します。

### [json_type](https://jansson.readthedocs.io/en/latest/apiref.html?#c.json_type) [ソースコードでの定義](https://github.com/akheron/jansson/blob/0dffb4284e7872c6e26956ad85fe127ba77220dc/src/jansson.h#L50-L59)

[json_t](https://jansson.readthedocs.io/en/latest/apiref.html?#c.json_t) は [json_type](https://jansson.readthedocs.io/en/latest/apiref.html#c.json_type) で表される型情報を保持しています。

|json_type|説明|判定関数|
|:--|:--|:--|
|JSON_STRING|文字列|json_is_string|
|JSON_INTEGER|整数|json_is_integer|
|JSON_REAL|実数|json_is_real|
|JSON_TRUE|TRUE|json_is_true|
|JSON_FALSE|FALSE|json_is_false|
|JSON_OBJECT|オブジェクト|json_is_object|
|JSON_ARRAY|配列|json_is_array|
|JSON_NULL|NULLオブジェクト|json_is_null|

* [json_typeof](https://jansson.readthedocs.io/en/latest/apiref.html#c.json_typeof) を使うことで  [json_t](https://jansson.readthedocs.io/en/latest/apiref.html?#c.json_t) のオブジェクトに関連付けられた [json_type](https://jansson.readthedocs.io/en/latest/apiref.html#c.json_type) を取得できます。
* 各タイプのどれに該当するかは、上記の表の判定関数(実際にはマクロ)で判定できます。
* JSON_ARRAY は配列なので、他の json_t オブジェクトを内部に保持できます。
* JSON_OBJECTはJSONオブジェクトなので他の json_t オブジェクトを内部に保持できます。
* JSON_ARRAYは配列なので整数のインデックスで子要素を識別して、取り出したり、設定したり、削除したりできます。
* JSON_OBJECTは子要素を文字列のキーで識別して、取り出したり、設定したり、削除したりできます。

### 凡例

|説明|参照カウンタ|
|--|--|
|参照カウンタを1に設定|1|
|参照カウンタを維持|→|
|参照カウンタをインクリメント|↑|
|参照カウンタをデクリメント|↓|

### [文字列](https://jansson.readthedocs.io/en/latest/apiref.html#string)

|関数名|説明|参照カウンタ|
|--|--|--|
|json_string|指定した文字列から、文字列型のjson_tオブジェクトを作成する。|1|
|json_stringn|指定した文字列から指定した文字数までの文字列型のjson_tオブジェクトを作成する。|1|
|json_string_value|文字列型のjson_tオブジェクトから文字列を取得する。|→|
|json_string_length|文字列型のjson_tオブジェクトの文字列長を取得する。|→|
|json_string_set|json_tオブジェクトに指定した文字列を設定する。|→|
|json_sprintf|sprintfのようにフォーマット指定した文字列のjsonオブジェクトを作成する。|1に設定|
|json_vsprintf|vsprintfのようにフォーマット指定した文字列のjsonオブジェクトを作成する。|1に設定|


### [数値](https://jansson.readthedocs.io/en/latest/apiref.html#number)

#### 整数

|関数名|説明|参照カウンタ|
|--|--|--|
|json_integer|整数から、整数型のjson_tオブジェクトを作成する。|1|
|json_integer_value|整数型のjson_tオブジェクトから整数を取得する。|→|
|json_integer_set|json_tオブジェクトに整数を設定する。|→|

#### 実数

|関数名|説明|参照カウンタ|
|--|--|--|
|json_real|実数から、実数型のjson_tオブジェクトを作成する。|1|
|json_real_value|実数型のjson_tオブジェクトから実数を取得する。|→|
|json_real_set|json_tオブジェクトに実数を設定する。|→|

#### 整数 または 実数

|関数名|説明|参照カウンタ|
|--|--|--|
|json_number_value|整数型または実数型のjson_tオブジェクトから実数を取得する。|→|

### [True, False, NULL](https://jansson.readthedocs.io/en/latest/apiref.html#true-false-and-null)

|関数名|説明|参照カウンタ|
|--|--|--|
|json_true|JSON trueオブジェクトを作成する|1|
|json_false|JSON falseオブジェクトを作成する|1|
|json_boolean|引数に応じてJSON trueオブジェクトまたはJSON falseオブジェクトを作成する|1|
|json_null|JSON NULLオブジェクトを作成する|1|

### [配列](https://jansson.readthedocs.io/en/latest/apiref.html#array)

|関数名|説明|参照カウンタ|python疑似コード|
|--|--|--|--|
|json_array|空の配列を作成する。|1|array = []|
|json_array_size|配列のサイズを取得する。|→|len(array)|
|json_array_get|配列の指定したインデックスのオブジェクトを取得する。|→|array[index]|
|json_array_set|(参照カウンタをインクリメントしたうえで)配列の指定したインデックスにオブジェクトを設定する。|↑|array[index] = x|
|json_array_set_new|(参照カウンタをインクリメントせずに)配列の指定したインデックスにオブジェクトを設定する。|→|array[index] = x|
|json_array_append|(参照カウンタをインクリメントしたうえで)配列の末尾にオブジェクトを追加する。|↑|array.append(x)|
|json_array_append_new|(参照カウンタをインクリメントせずに)配列の末尾にオブジェクトを追加する。|→|array.append(x)|
|json_array_insert|(参照カウンタをインクリメントしたうえで配列の指定した位置に)オブジェクトを挿入する。|↑|array.insert(index, x)|
|json_array_insert_new|(参照カウンタをインクリメントせずに)配列の指定した位置にオブジェクトを挿入する。|→|array.insert(index, x)|
|json_array_remove|(参照カウンタをデクリメントして)配列の指定した位置のオブジェクトを削除する。|↓|del array[index]|
|json_array_clear|(参照カウンタをデクリメントして)配列のすべてのオブジェクトを削除する。|↓|del array[:]|
|json_array_extend|(参照カウンタをインクリメントして)別の配列オブジェクトの中身を配列の最後に追加する。|↑|array1.extend(array2)|
|json_array_foreach(array,index,value)|配列オブジェクトに対するループ処理。indexとvalueが利用できる。|→|for i, value in enumerate(array)|


### [オブジェクト](https://jansson.readthedocs.io/en/latest/apiref.html#object)

|関数名|説明|参照カウンタ|python疑似コード|
|--|--|--|--|
|json_object|空のオブジェクトを作成する。|1|object = {}|
|json_object_size|オブジェクトのサイズを取得する。|→|len(object)|
|json_object_get|指定したキーを持つオブジェクトを取得する。|→|object[key]|
|json_object_set|(参照カウンタをインクリメントして)指定したキーにオブジェクトを設定する。|↑|object[key] = x|
|json_object_set_new|(参照カウンタをインクリメントせずに)指定したキーにオブジェクトを設定する。|→|object[key] = x|
|json_object_del|(参照カウンタをデクリメントして)指定したキーのオブジェクトを削除する。|↓|del object[key]|
|json_object_clear|(参照カウンタをデクリメントして)すべてのオブジェクトを削除する。|↓|object.clear()|
|json_object_update|別のオブジェクトのキーをマージする。存在しないキーを持つオブジェクトは追加される。同じキーを持つオブジェクトは上書きされる。|↑|object1.update(object2)|
|json_object_update_existing|別のオブジェクトのキーをマージする。同じキーを持つオブジェクトのみ上書きされる。存在しないキーを持つオブジェクトは更新されない。|↑||
|json_object_update_missing|別のオブジェクトのキーをマージする。同じキーを持つオブジェクトは更新されない。存在しないキーを持つオブジェクトは追加される。|↑||
|json_object_update_recursive|再帰的にjson_object_updateを実行する。|↑||
|json_object_foreach(object,key,value)|オブジェクトに対するループ処理。indexとvalueが利用できる。|→|for key, value in object.items()|
|json_object_foreach_safe(object,key,value)|オブジェクトに対するループ処理。indexとvalueが利用できる。ループ処理中にjson_object_delができる。|→|for key, value in object.items()|


イテレータで列挙

```c
/* obj is a JSON object */
const char *key;
json_t *value;

void *iter = json_object_iter(obj);
while(iter)
{
    key = json_object_iter_key(iter);
    value = json_object_iter_value(iter);

    /* use key and value ... */
    iter = json_object_iter_next(obj, iter);
}
```


### [json_error_t](https://jansson.readthedocs.io/en/latest/apiref.html#c.json_error_t) [ソースコードでの定義](https://github.com/akheron/jansson/blob/0dffb4284e7872c6e26956ad85fe127ba77220dc/src/jansson.h#L152-L158)

エラーの通知に使用する型です。
[json_loads](https://jansson.readthedocs.io/en/latest/apiref.html#c.json_loads) など内部でメモリ確保するなど失敗する可能性のある関数の引数に渡してエラーの詳細を取得するときに使います。[json_error_t](https://jansson.readthedocs.io/en/latest/apiref.html#c.json_error_t) の構造体の実体は呼び出し元で確保します。

## 入出力操作

### ファイルからの読み込み

|関数名|説明|入力|出力|
|--|--|--|--|
|json_loads|NULL終端された文字列から読み取って json_tオブジェクトツリーを構築する。|文字列(サイズ指定なし)|json_tオブジェクト|
|json_loadb|指定した長さの文字列から読み取って json_tオブジェクトツリーを構築する。|文字列(サイズ指定あり)|json_tオブジェクト|
|json_loadf|FILEポインタのファイルから読み取って json_tオブジェクトツリーを構築する。|ファイル(FILEポインタ指定)|json_tオブジェクト|
|json_loadfd|file descriptorのファイルから読み取って json_tオブジェクトツリーを構築する。|ファイル(file descriptor指定)|json_tオブジェクト|
|json_load_file|指定したファイル名のファイルを開いて読み取って json_tオブジェクトツリーを構築する。|ファイル(ファイル名指定)|json_tオブジェクト|


### ファイルへの書き込み

|関数名|説明|入力|出力|
|--|--|--|--|
|json_dumps|指定した json_t オブジェクトを整形してメモリを確保したうえで文字列で出力する。使い終わったらメモリを解放する必要がある。|json_tオブジェクト|文字列(ライブラリ側でメモリ確保)|
|json_dumpb|指定した json_t オブジェクトを整形して渡されたバッファに文字列で出力する。必要なバッファサイズを返す。|json_tオブジェクト|文字列(呼び出し側でメモリ確保)|
|json_dumpf|指定した json_t オブジェクトを整形してFILEポインタのファイルに出力する。|json_tオブジェクト|ファイル(FILEポインタ指定)|
|json_dumpfd|指定した json_t オブジェクトを整形してfile descriptorのファイルに出力する。|json_tオブジェクト|ファイル(file descriptor指定)|
|json_dump_file|指定した json_t オブジェクトを整形して指定したファイル名のファイルに出力する。|json_tオブジェクト|ファイル(ファイル名指定)|