JSONを埋め込みに埋め込みますか? それと同じくらい簡単

画像



少し前までは、非常に限られたリソースでアプリケーション構成をロードする必要がありました。 標準のC関数にはほとんどアクセスできませんでしたが、メモリmalloc()/ free()を操作するための標準関数があることは非常に幸運でした。



次の状況が発生しました。リソースが限られているシステムにアプリケーションをロードすると、構成がファイルから読み取られます。 構成自体は通常のコンピューターで簡単に編集する必要がありますが、顧客に説明する際にオブジェクトのいくつかの値をすばやく直接修正する必要があるまでです。



これから、次のいずれかを行う必要があると結論付けることができます。

  1. 独自のバイナリ形式エディターを作成します。
  2. テキスト形式を使用します。




最初のオプションは、その制限とスケーラビリティのために私たちには適していません。 いくつかの新しいフィールドをバイナリファイルの構造に追加する場合、ファイルエディターを(最高で)再コンパイルする必要があります。 したがって、2番目のオプションを使用します。



しかし、特にすべてが私たちの前で発明されたので、私はテキスト形式をフェンスしたくありませんでした。 同様の問題を抱えているのは私たちが初めてではありません。 したがって、データを格納するための多かれ少なかれ標準的なテキスト形式のいずれかを使用します。



そのような選択肢があります:





XMLが私たちのタスクには余りにも冗長だったため、すぐに削除されたとすぐに言います。 YAMLは興味深い形式ですが、まだかなり狭い範囲に広がっています。 `key = value`タイプのファイルは単純すぎます。 それらに複雑な値を格納することは非常に困難です。 ここでこの形式の日付で正確な時間を保存するか、各値(year = ...、month = ...、...、second = ...)に独自のキーを記述してください。これは単なる解析ですが、ひどく見えます日付パーサーを「date = 2005-08-09T18:31:42」の値に書き込みます。 そして、50のフィールドがある従業員を表すエッセンスを保存する必要がありますか? 同じ理由で、INIファイルはドロップされます。 Lua-configsは非常に興味深いものであり、非常に簡単に統合できるため、多くのチャンスがあります。 しかし、再び、テキストファイルを解析するために仮想マシンを起動したくありませんでした。



したがって、最終的にはJSONを選択しました。 十分に一般的です。 十分な拡張性。 編集と学習が簡単(セミITスペシャリストによる編集が必要な場合)。



したがって、フォーマットを決定しましたが、依存関係のないこのフォーマットのパーサーを見つけることは残っています...ですから、やめてください。 このような「フィルター」で見つかった唯一のものは、 jsmnパーサーでした。 しかし、問題はこれがパーサーであることです。 JSONオブジェクトを形成するのではなく、文字列をトークンに解析するだけです。 ダウンロードした* .jsonファイルの形式が事前にわかっている場合は、すべての値を取得できます。 ただし、ダウンロードしたファイルの形式が事前にわかっている場合は、バイナリ形式を使用しないでください。 したがって、ファイル形式がわからないとします。 したがって、jsmnのラッパーをすばやく作成します。



そして、 Json For Embedded Systems (JFES)プロジェクトが誕生しました。



主な機能





JFESライブラリは、jfes.hとjfes.cの2つのファイルに基づいており、すべてが回転するオブジェクトはjfes_value_tです。



/** JSON value structure. */ struct jfes_value { jfes_value_type_t type; /**< JSON value type. */ jfes_value_data_t data; /**< Value data. */ };
      
      





次に、タイプフィールドは値をとることができます。



 /** JFES token types */ typedef enum jfes_token_type { jfes_undefined = 0x00, /**< Undefined token type. */ jfes_null = 0x01, /**< Null token type. */ jfes_boolean = 0x02, /**< Boolean token type. */ jfes_integer = 0x03, /**< Integer token type. */ jfes_double = 0x04, /**< Double token type. */ jfes_string = 0x05, /**< String token type. */ jfes_array = 0x06, /**< Array token type. */ jfes_object = 0x07, /**< Object token type. */ } jfes_token_type_t; /** Json value type is the same as token type. */ typedef jfes_token_type_t jfes_value_type_t;
      
      





そして、データフィールドは結合です:



 /** JFES value data union. */ typedef union jfes_value_data { int bool_val; /**< Boolean JSON value. */ int int_val; /**< Integer JSON value. */ double double_val; /**< Double JSON value. */ jfes_string_t string_val; /**< String JSON value. */ jfes_array_t *array_val; /**< Array JSON value. */ jfes_object_t *object_val; /**< Object JSON value. */ } jfes_value_data_t;
      
      





初期化



ライブラリを初期化するには、jfes_config_tオブジェクトを初期化する必要があります。



 /** JFES config structure. */ typedef struct jfes_config { jfes_malloc_t jfes_malloc; /**< Memory allocation function. */ jfes_free_t jfes_free; /**< Memory deallocation function. */ } jfes_config_t;
      
      





JFESは完全に依存関係がないと言ったことを覚えていますか? つまり、彼女自身もメモリの割り当て方法を知らず、そのソースには単一の#includeはありません。 必要に応じて、デバッグの目的で、割り当てられたメモリを確認するか、メモリ管理機能のみがあるため、メモリ割り当て関数を指定できます。



 jfes_config_t config; config.jfes_malloc = malloc; config.jfes_free = free;
      
      





それだけです! その後、好きなようにjson文字列を解析できます。 任意の値を編集して、行に再度保存できます。 JFESでの作業の小さな例。



このようなJSONを解析します。



 { "first_name": "John", "last_name": "Black", "age": 35, "children": [ { "first_name": "Alice", "age": 5 }, { "first_name": "Robert", "age": 8 }, ], "wife": null, "simple" : [ 12, 15, 76, 34, 75, "Test", 23.1, 65.3, false, true, false ] }
      
      





このコードを使用して解析します。



 jfes_config_t config; config.jfes_malloc = malloc; config.jfes_free = free; jfes_value_t value; jfes_parse_to_value(&config, json_data, json_size, &value); /*     children.    ,  children  JFES_NULL. */ jfes_value_t *children = jfes_get_child(&value, "children", 0); /*          .  : 1.  . 2.   . 3.    . */ jfes_value_t *child = jfes_create_object_value(&config); /*     "Paul"      "first_name". */ jfes_set_object_property(&config, child, jfes_create_string_value(&config, "Paul", 0), "first_name", 0); /*      "middle_name"  "age". */ jfes_set_object_property(&config, child, jfes_create_string_value(&config, "Smith", 0), "middle_name", 0); jfes_set_object_property(&config, child, jfes_create_integer_value(&config, 1), "age", 0); /*    2.  :       ,    .    ,   . */ jfes_set_object_property(&config, child, jfes_create_integer_value(&config, 2), "age", 0); /*    child  "middle_name" */ jfes_remove_object_property(&config, child, "middle_name", 0); /*   `child`   `children`   1. */ status = jfes_place_to_array_at(&config, children, child, 1); jfes_set_object_property(&config, &value, jfes_create_null_value(&config), "null_property", 0); /*       .  dump_size,  ,     .    -.      1,  0,       ,  ,   .. (ugly). */ jfes_size_t dump_size = 1024; char *beauty_dump = malloc(dump_size * sizeof(char)); jfes_value_to_string(&value, &beauty_dump[0], &dump_size, 1); beauty_dump[dump_size] = '\0'; free(beauty_dump); /*         . */ jfes_free_value(&config, &value);
      
      





あとがき



ライブラリは、他のコードのように完璧ではありません。 エラー、省略、タイプミスがあります。 しかし、これがオープンソースの力です。 プルリクエスト、コメント、チケット、要望に喜んで対応いたします。



私のgithubへのリンク: JFES



少なくとも誰かがそれを有用であり、自転車の建設の1週間を節約できることを願っています。 私の強さと能力の範囲で、それを修正します。 毎晩のコミットはすべて実験ブランチ、マスターで行われ、多少安定したテスト済みのコードがマージされます。 例外はアルファステージのみです。製品がアルファ版の場合、マスターブランチは破損する可能性がありますが、可能な限り実験的なものを使用して、何も破損しないようにします。



バージョン1.0.0より前では、APIが変更される可能性がありますので、注意してください。 ただし、APIの変更はcommit`aの説明に記述されます。



jsmnライブラリのzsergeに感謝します。



頑張って!



All Articles