Spaghetti Code Monster

きれいなコードを読み書きしたい.

Parsonを使って,JSONのデータをCの構造体に変換する

はじめに

モダンな言語(Goとか,Python)には,JSONをパースしてくれる便利なライブラリが標準で利用できるようになっています.
しかし,C言語にはそのような素晴らしいものは標準ライブラリにはありません.

そこで,C言語JSONをパースしたいときに,どういう方法があるか調べました.

Parson

Parsonというライブラリがありました. mattn.kaoriya.net kgabis.github.io 上記リンクに,大まかな使い方が記載されています.
ドットを使って,アクセスしたいJSONデータのパスを指定できるようです.

Parsonを試す

試しに適当なデータを作り,ParsonでJSONのデータをCの構造体に変換してみました.

お試しデータ

{
  "name": {
    "first": "John",
    "last": "Doe"
  },
  "age": 33
}

このデータを,"personal.json"という名前で保存して使用します.

実装したコード

#include <stdio.h>
#include <tchar.h>
#include <string.h>

#include "parson.h"

#define NAME_MAX 32

#define JSON2STRUCT_STR(_json, _struct, _key, _size)                        \
do{                                                                          \
   strncpy(_struct._key, json_object_dotget_string(_json, #_key),_size); \
} while (0);                                                                \

#define JSON2STRUCT_NUM(_json, _struct, _key)                   \
do {                                                         \
   _struct._key = json_object_dotget_number(_json, #_key);  \
}while(0); 

#define JSON2STRUCT_BOOL(_json, _struct, _key)                  \
do {                                                         \
   _struct._key = json_object_dotget_boolean(_json, #_key); \
}while(0); 


typedef struct _NAME {
    char first[NAME_MAX + 1];
    char last[NAME_MAX + 1];
} Name;

typedef struct _PERSONINFO {
    Name name;
    unsigned int age;
}PERSON_INFO;

int main(void)
{
    JSON_Value *root_value = json_parse_file("./personal.json");
    JSON_Object *root = json_object(root_value);

    PERSON_INFO person;
    
    JSON2STRUCT_NUM(root, person, age);
    JSON2STRUCT_STR(root, person, name.first, NAME_MAX);
    JSON2STRUCT_STR(root, person, name.last, NAME_MAX);

    json_value_free(root_value);

    printf("name.first:%s\n", person.name.first);
    printf("name.last:%s\n", person.name.last);
    printf("name.age:%d\n", person.age);
    
    return 0;
}

実行結果

name.first:John
name.last:Doe
name.age:33

ドットで,アクセスしたい場所を指定できるのがかなりいい感じです.
ただし,json_object_dotget_number関数など,数値を取得する関数が, 失敗したときに0を返すのが気になりました.

8/7追記

GCCでエラーになっていたのでコードを修正.