LoginSignup
2
2

More than 5 years have passed since last update.

yajl-dの使い方

Last updated at Posted at 2014-10-04

READMEは英語で書かれているので,日本語でyajl-dについて紹介する記事です.内容は執筆時点でのバージョンである0.2.0です.

yajl-d

yajl-dはyajlのD言語バインディングです.標準のstd.jsonはちょっと使う分には良いんですが,オブジェクトからのマッピングがなかったり,ストリーミング的にデコード出来なかったりと,いくつか欲しい機能がなかったので作りました.

インストール

まずyajl本体をインストール.大抵各OSにはパッケージがあると思います.Macならhomebrewを使えば楽です.

brew install yajl

yajl-dはyajlという名前でdubに登録してあるので,dub.jsonのdependenciesに追加すれば利用出来ます.以下は単純な例です.

  "dependencies": {
    "yajl": ">=0.1.2"
  }

yajlを使うには以下のようにimportします.

import yajl;

API

encode(value) / decode(json)

単にJSONを扱うだけであれば,encode/decodeのペアが楽です.encodeにはJSONにシリアライズしたいオブジェクトを,decodeにはJSON文字列を渡します.
また,decodeのtemplateパラメータには,JSONにマッピングしたい型を指定します.指定しなければ,std.json.JSONValueが返ります.

import yajl;

struct Hoge
{ 
    ulong id;
    string word;
    bool yes; 
}

void main()
{
    // json is {"id":100,"word":"hey!","yes":true}
    string json = encode(Hoge(100, "hey!", true));

    // Convert decoded result into Hoge
    Hoge hoge = decode!Hoge(json);
    assert(hoge.id == 100);

    // The default return type is std.json.JSONValue
    JSONValue jv = decode(json);
    assert(jv["id"].integer == 100);
}

独自のJSON型を作らずにstd.json.JSONValueを使ったのは,JSON型の実装としてstd.json.JSONValueは基本的な機能を備えていたからです.

encode(value, opt) / decode(json, opt)

encode/decodeの第二引数にオプションを渡すバージョンです.

  • Encoder.Option

オプション群は以下のようになっています.詳細を説明するのが面倒なので,yajlの説明を参照してください.

static struct Option
{
    bool beautify;
    bool validateUTF8;
    bool escapeSolidus;
    string indentString;
}

  • Decoder.Option

Encoder.Optionと同じく,詳細はyajlの説明を参照してください.missingHandlerはyajl-d独自のもので,後で説明します.

static struct Option
{
    bool allowComments;
    bool dontValidateStrings;
    bool allowTrailingGarbage;
    bool allowMultipleValues;
    bool allowPartialValue;

    MissingHandler missingHandler;
}

両方とも,Optionを生成して第二引数に渡すだけです.以下はdecodeの例です.

Decoder.Option opt;
opt.allowComments = true;
decode(json, opt);

Encode / Decoder

encode/decodeは,中ではEncoderDecoderを使っています.この二つを直接使えば,インスタンス生成を抑えてパフォーマンスが改善でき,ストリーミング的にデコードが出来たりします.

Encoderはかなりシンプルな実装になっています.encode(value)の中身は以下のようになっています.

Encoder encoder;
encoder.encode(value);

// Encoderを使い回すことで生成コストを抑えられる
encoder.encode(value2);

Decoderは実装がそもそもStreaming Decoderになっていて,少しAPIがEncoderとは違います.以下がdecodeの中身です.

Decoder decoder;
if (decoder.decode(json))
    return decoder.decodedValue!T;

decodeではデコード出来たかどうかが真偽値で返ってきます.falseだった場合には不完全なJSONが渡ってきたということで,次のdecode呼び出しにさらにJSONを渡せます.ネットワーク上だと断続的にデータが渡ってきたりするので,そのような場合に効率的にデコード出来るようになってます.
その後,decodedValueを呼び出すことで,デコード結果を取得出来ます.

Decoderは内部に状態を持っていて,デフォルトでは複数JSONを連続してデコード出来なくなっています.インスタンスを使い回して効率的にデコードするには,以下のようにオプションを指定します.

Decoder.Option opt;
opt.allowMultipleValues = true;
Decoder decoder = Decoder(opt);
foreach (j; jsons) {
    decoder.decode(j);
    decoder.decodedValue;
}

JSONでキーが足りない時にコールバックする

Decoder.OptionmissingHandlerをセットすると,受け取ったJSONを構造体に変換する時にキーが見つからなければ,そのキーを引数にコールバックが呼ばれます.

struct Test
{
    string name;
    int age;
}

void main()
{
    auto encoded = `{ "name": "Bob", "age": 20}`;
    auto missing = `{ "name": "Bob"}`;

    Decoder.Option opt;
    opt.missingHandler = (string field) { writeln(field); };
    writeln(decode!Test(encoded, opt));
    writeln(decode!Test(missing, opt)); // Callback called with missing field
}

D言語のキーワードを持つJSONを扱う

今までの例を見れば分かるように,yajl-dは構造体やクラスをエンコード/デコードするときに,各メンバの名前を自動的にキーにします.しかし,D言語は予約語は変数名に出来ないので,そのようなJSONはデフォルトでは上手く扱えません.
このケースに対応するには,JSONNameアノテーションを使います.以下のように対象のメンバに対してJSONNameを使い,マッピング先を指定出来ます.

struct Hoge
{ 
    ulong id;
    @JSONName("body") string _body;
    bool yes; 
}

// {"id":100,"body":"hey!","yes":true}
string json = encode(Hoge(100, "hey!", true));

この機能はAdamさんから頂いたパッチで実現しました.

パフォーマンス

手元のMBPでstd.json,vibe.data.json,yajlを使って,構造体をJSON文字列へのエンコード,JSON文字列をJSON型へデコードするのを簡単に比較してみた所,とりあえず一番速かった(ソースはココ).

encode:
json: 229240 QPS
vibe: 416995 QPS
yajl: 624793 QPS
decode:
json: 230197 QPS
vibe: 271000 QPS
yajl: 440328 QPS

Encoder/Decoderを使って複数JSONを処理すれば,もっとパフォーマンスが出ます.これに関してはREADMEのパフォーマンスの所を見てください.

まとめ

yajl-d,yajl依存があるのでstd.jsonほど手軽ではないですが,色々と追加機能もありパフォーマンスもいいので,何かD言語でJSONを扱うことがあれば,検討してみてください :)

2
2
0

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
2
2