LoginSignup
13
14

More than 5 years have passed since last update.

Crystal で JSON を高速パースする

Last updated at Posted at 2015-08-30

Crystal で JSON パースするには ?

Ruby 風の静的言語 Crystal で JSON をパースするには、以下の 2 つの方法があります。

  • JSON::Parser を使う方法
  • JSON::Mapping を使う方法

JSON::Parser は、どんな型が入っているかが未定な JSON に有効な方法で、変換後の型を確かめながら (もしくは強制的に型を変換し) 値を取得します。特に動的言語で有効なアプローチです。

JSON::Mapping は、事前にどのような型が入っているかを定義し、それに従ってパースする方法です。こちらのほうが高速で、変換後の値も扱いやすいのでオススメです。この記事では、こちらを解説します。

JSON::Mapping を使ってパースする方法

今回変換するのは、イベント管理サイト Connpass の API 出力です。

JSON::Mapping を使ってパースするには、はじめに JSON の構造の定義をし、その定義を用いてパースします

JSON 構造の定義

JSON 構造を定義するには、json_mapping マクロを使います。引数は { key: Type } の形式で指定します。値に null が来る可能性がある場合は、{ key: { type: Type, nilable: true } のように指定します。

require "json"

module Response
  class Result
    JSON.mapping({
      results_returned: Int32,
      results_available: Int32,
      results_start: Int32,
      events: Array(Event),
    })
  end

  class Event
    JSON.mapping({
      event_id: Int32,
      title: { type: String, nilable: true },
      catch: { type: String, nilable: true },
      description: { type: String, nilable: true },
      event_url: { type: String, nilable: true },
      hash_tag: { type: String, nilable: true },
      started_at: { type: String, nilable: true },
      ended_at: { type: String, nilable: true },
      limit: { type: Int32, nilable: true }, 
      event_type: { type: String, nilable: true },
      series: { type: Series, nilable: true },
      address: { type: String, nilable: true },
      place: { type: String, nilable: true },
      lat: { type: String, nilable: true },
      lon: { type: String, nilable: true },
      owner_id: { type: Int32, nilable: true }, 
      owner_nickname: { type: String, nilable: true },
      owner_display_name: { type: String, nilable: true },
      accepted: { type: Int32, nilable: true }, 
      waiting: {type: Int32, nilable: true },
      updated_at: { type: String, nilable: true },
    })
  end

  class Series
    JSON.mapping({
      id: Int32,
      title: { type: String, nilable: true },
      url: { type: String, nilable: true },
    })
  end
end

JSON のパース

上記で定義した構造を用いて、JSON を実際にパースするには、以下のようにします。

require "json"
require "http/client"

# HTTP リクエストを投げて JSON を取得する
res = HTTP::Client.get("http://connpass.com/api/v1/event/?keyword=Ruby")
body = res.body

# 定義した構造を元に JSON をパースする
# 変換結果は Response::Result のインスタンスとして取得されます
result = Response::Result.from_json(body)

p result.title

まとめ

JSON::Mapping を使うと、簡単・高速に JSON パースが可能です。標準 API なので、積極的に使いましょう。

参考文献

13
14
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
13
14