C/C++でJSONを読み込む(JSON-Cの使用方法まとめ)

# TL;DR
libjson(JSON-C)を使ってJSONファイルをパースする方法を調べたので、記事にしようと思います。

# 追記 (2016/2/9)
C言語向けでも他に `jansson` または `jsmn` などもあるようですので、検討しても良いと思います。
振り返って考えると `json-c` はドキュメントの少なさと実装の癖が強いのであんまりオススメできません・・・。

[Big Sky :: C言語から使えるJSONパーサ、jansson がとても直感的で良い](http://mattn.kaoriya.net/software/lang/c/20130710214647.htm)
[Big Sky :: C言語から使えるJSONパーサ、JSMNを試してみた。](http://mattn.kaoriya.net/software/lang/c/20120822011026.htm)

C++向けでは `picojson` あたりが有名ドコロです。C++向けでは検索するといろいろ出てきますので、さほど困らないと思います。

[kazuho/picojson: a header-file-only, JSON parser serializer in C++](https://github.com/kazuho/picojson)
[Big Sky :: ヘッダファイルだけでC++から使えるJSONパーサ「picojson」が凄い！](http://mattn.kaoriya.net/software/lang/c/20090702153947.htm)

ただ、`picojson` はやたらバイナリサイズが大きくなった印象があるので、そこらへん気にする場合は気をつけて下さい。

# libjson (JSON-C) の使用方法
(上の追記であまりオススメしませんと書いてはいますが、日本語資料はあんまりないのでそのままにしておきます)

## 読み込む対象ファイル
とりあえず一通り使える形式を抑えました。

```js:config.json
{
    'test_integer' : 12345,
    'test_double' : 987.654321,
    'test_string' : "joys of programming",
    'test_boolean' : true,
    'test_array' : [
        "c",
        "c++",
        "d",
        "lisp",
    ],
    'test_object' : {
        'test_integer' : 54321,
        'test_double' : 123456.789,
        'test_string' : "hello world",
        'test_boolean' : false,
        'test_array' : [
            "perl",
            "golang",
            "whitespace",
            "lua",
        ],
    },
}
```

## テストコード
パースして値を読むテストコード。わりと簡単に実装できました。

文字列からでも、ファイルからでも大丈夫です。
ざっと書いたので間違ってたらすみません。

'json_object_object_foreach'の'key'とか'val'の宣言がないのは、
json.h内の、関数マクロでなんやかんややっているからです（ここがちょっと気持ち悪い）

```cpp:json-c_test
#include <stdio.h>
#include <json/json.h>

void test_parse_obj_to_string(struct json_object* const obj) {
    json_object_object_foreach(obj, key, val) {
        printf("-- \t%s: %s\n", key, json_object_to_json_string(val));
    }
}

void test_parse_check_type(struct json_object* const obj) {
    json_object_object_foreach(obj, key, val) {
        if (json_object_is_type(val, json_type_null)) {
            printf("-- \tjson_type_null -> \t%s: %s\n",
                    key, json_object_to_json_string(val));
        }
        if (json_object_is_type(val, json_type_boolean)) {
            printf("-- \tjson_type_boolean -> \t%s: %s\n",
                    key, json_object_to_json_string(val));
            printf("-- \t\tvalue: %s\n", json_object_get_boolean(val)? "true": "false");
        }
        if (json_object_is_type(val, json_type_double)) {
            printf("-- \tjson_type_double -> \t%s: %s\n",
                    key, json_object_to_json_string(val));
            printf("-- \t\tvalue: %lf\n", json_object_get_double(val));
        }
        if (json_object_is_type(val, json_type_int)) {
            printf("-- \tjson_type_int -> \t%s: %s\n",
                    key, json_object_to_json_string(val));
            printf("-- \t\tvalue: %d\n", json_object_get_int(val));
        }
        if (json_object_is_type(val, json_type_object)) {
            printf("-- \tjson_type_object -> \t%s: %s\n",
                    key, json_object_to_json_string(val));
            printf(">>> START object \n");
            test_parse_check_type(val);
            printf("<<< END object \n");
        }
        if (json_object_is_type(val, json_type_array)) {
            printf("-- \tjson_type_array -> \t%s: %s\n",
                    key, json_object_to_json_string(val));

            for (int i = 0; i < json_object_array_length(val); ++i) {
                struct json_object *a = json_object_array_get_idx(val, i);
                printf("-- \t\tvalue: [%d]=%s\n", i, json_object_to_json_string(a));
            }
        }
        if (json_object_is_type(val, json_type_string)) {
            printf("-- \tjson_type_object -> \t%s: %s\n",
                    key, json_object_to_json_string(val));
            printf("-- \t\tvalue: %s\n", json_object_get_string(val));
        }
    }
}

int main() {
    puts("\n== json parse test start");

    puts("\n== json parse from srting");
    struct json_object *jobj_from_string = json_tokener_parse("{'a':1,'b':2,'c':3}");
    test_parse_obj_to_string(jobj_from_string);

    puts("\n== json parse from file");
    struct json_object *jobj_from_file = json_object_from_file("./config.json");
    test_parse_obj_to_string(jobj_from_file);

    puts("\n== json parse from file & check type");
    test_parse_check_type(jobj_from_file);

    return 0;
}
```

https://github.com/koara-local/json-test

## ログ出力結果

```
== json parse test start

== json parse from srting
-- 	a: 1
-- 	b: 2
-- 	c: 3

== json parse from file
-- 	test_integer: 12345
-- 	test_double: 987.654321
-- 	test_string: "joys of programming"
-- 	test_boolean: true
-- 	test_array: [ "c", "c++", "d", "lisp" ]
-- 	test_object: { "test_integer": 54321, "test_double": 123456.789000, "test_string": "hello world", "test_boolean": false, "test_array": [ "perl", "golang", "whitespace", "lua" ] }

== json parse from file & check type
-- 	json_type_int -> 	test_integer: 12345
-- 		value: 12345
-- 	json_type_double -> 	test_double: 987.654321
-- 		value: 987.654321
-- 	json_type_object -> 	test_string: "joys of programming"
-- 		value: joys of programming
-- 	json_type_boolean -> 	test_boolean: true
-- 		value: true
-- 	json_type_array -> 	test_array: [ "c", "c++", "d", "lisp" ]
-- 		value: [0]="c"
-- 		value: [1]="c++"
-- 		value: [2]="d"
-- 		value: [3]="lisp"
-- 	json_type_object -> 	test_object: { "test_integer": 54321, "test_double": 123456.789000, "test_string": "hello world", "test_boolean": false, "test_array": [ "perl", "golang", "whitespace", "lua" ] }
>>> START object 
-- 	json_type_int -> 	test_integer: 54321
-- 		value: 54321
-- 	json_type_double -> 	test_double: 123456.789000
-- 		value: 123456.789000
-- 	json_type_object -> 	test_string: "hello world"
-- 		value: hello world
-- 	json_type_boolean -> 	test_boolean: false
-- 		value: false
-- 	json_type_array -> 	test_array: [ "perl", "golang", "whitespace", "lua" ]
-- 		value: [0]="perl"
-- 		value: [1]="golang"
-- 		value: [2]="whitespace"
-- 		value: [3]="lua"
<<< END object
```

# 参考
[json-c/json-c](https://github.com/json-c/json-c)
今回使用させて頂いたJSONパーサ

[JSON の紹介](http://json.org/json-ja.html)
最初は、TOPの図を見てもなんのこっちゃわかりませんでしたが、コード書いてみるととてもわかり易い図です

[json-c / libjson Tutorial with Examples](http://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/)
エスケープがちょこちょこエラッタしてますが、Exampleがとても助かりました。
というかJSON-CのExampleが公式に見当たらなかったので、このページを見ると良いと思います