LoginSignup
3
3

More than 3 years have passed since last update.

JSONファイルパーサparsonでJSONを成型する方法

Last updated at Posted at 2019-09-19

はじめに

JSONパーサのparsonが便利だったのでまとめておきます。今回はJSONの読み込みではなく成型に絞った内容です。JSONって何?という方はこちら

最も単純な例

細かい話は後回しにして、単純な例を見てみましょう。

tutorial.c
    JSON_Value* test_val = json_value_init_object(); // オブジェクトと紐づくよう初期化
    JSON_Object* test_obj = json_value_get_object(test_val); // 紐づける

    // メンバをセット
    json_object_set_string(test_obj, "key_str", "example");
    json_object_set_number(test_obj, "key_num", 1.0);
    json_object_set_boolean(test_obj, "key_bool", true);

    // 何かしらの処理

    // 最後に解放処理
    json_value_free(test_val);

結果は以下の通りです。

{
    "key_str": "example",
    "key_num": 1,
    "key_bool": true
}

一番ややこしいのは、JSON_ValueとJSON_Objectの2つが存在するところです。
JSON_Valueについては後で説明するので一旦保留にしておきます。
一方、JSON_Objectとは、中カッコで囲まれ、中にいくつかメンバを持つもので、単にオブジェクトと呼んでいるものです(まさに上に表示されているもの)。

JSON_Valueとは?

こちらでも紹介されているように、バリューとして取り得る型には6つの種類があります。JSON_Valueとは、その6種類のどれとでも紐づくことができる、より上位の存在です。

上の例では、

  • バリューを「あなたはオブジェクトと紐づくんですよ」と初期化
  • 実際にオブジェクトと紐づける
  • オブジェクトの方にメンバをセットしていく

という流れになっています。

上の例だけを見ていると、「JSON_Valueなんていらないのでは?」と思ってしまうかもしれませんが、これが後々になって生きてきます。

もっと複雑なJSONを作りたい!

上記の例では、バリューの型としてそれぞれ文字列・数値・booleanの3つをセットできました。基本はこれで押さえているのですが、先ほど作ったJSONを、下のようにさらに入れ子にするにはどうすればいいでしょうか?

{
    "key_obj": {
        "key_str": "example",
        "key_num": 1,
        "key_bool": true
    }
}

てっきりjson_object_set_object()のような関数があるかと思いきや、実は、文字列や数値の場合とは異なり、オブジェクトを直接セットする関数はないんです。私はここで詰まりました。

間接的にオブジェクトをセットする

JSON_Objectは直接セットできません。その代わりに、JSON_Valueをセットする関数json_object_set_value()が用意されています。この関数を使って入れ子にしたコードがこちら。

object.c
    // 親となるオブジェクトを作成
    JSON_Value* root_val = json_value_init_object();
    JSON_Object* root_obj = json_value_get_object(root_val);

    // 入れ子になるオブジェクトを作成
    JSON_Value* test_val = json_value_init_object();
    JSON_Object* test_obj = json_value_get_object(test_val);

    json_object_set_string(test_obj, "key_str", "example");
    json_object_set_number(test_obj, "key_num", 1.0);
    json_object_set_boolean(test_obj, "key_bool", true);

    // 親オブジェクトにメンバをセット
    json_object_set_value(root_obj, "key_obj", test_val);

    // 何かしらの処理

    // 最後に親のみ解放
    json_value_free(root_val);

繰り返しになりますが、結果は以下の通りです。

{
    "key_obj": {
        "key_str": "example",
        "key_num": 1,
        "key_bool": true
    }
}

さらに外側に親となるJSON_Objectを作り、json_object_set_value()を呼ぶのがミソです。
ちなみに、最後の解放処理は、どれだけ入れ子になっても最上位さえ解放すればOKです。

間接的に配列をセットする

オブジェクトと同じようにして配列もセットすることができます。
オブジェクトの場合と流れは同じですが、初期化や要素の追加方法が若干異なります。

array.c
    // 親となるオブジェクトを作成
    JSON_Value* root_val = json_value_init_object();
    JSON_Object* root_obj = json_value_get_object(root_val);

    // 配列を作成
    JSON_Value* test_val = json_value_init_array();
    JSON_Array* test_arr = json_value_get_array(test_val);

    json_array_append_string(test_arr, "example1");
    json_array_append_string(test_arr, "example2");

    // 親オブジェクトにメンバをセット
    json_object_set_value(root_obj, "key_arr", test_val);

    // 何かしらの処理

    // 最後に親のみ解放
    json_value_free(root_val);

結果は以下の通りです。

{
    "key_arr": [
        "example1",
        "example2"
    ]
}

まとめ

以上のコードを流用すれば、入れ子式に複雑なJSONも成型することができるはずです。
もっと効率のいい方法は、こちらのSerializationを参考にどうぞ。dotset系の関数を使うともっとシンプルにできます。

3
3
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3