その他
    ホーム 技術発信 DoRuby json の憂鬱

    json の憂鬱

    この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

    現在ではxmlよりもyml よりも使われているであろう構造化文書の形式json。自分がド新人だったときに、「json? なんて不吉な名前の変数なんだ」と思ったのも遠い昔のことです。

    json を始めとする構造化文書の便利さは、適切なライブラリを使えば 言語内の変数(hash, array 等)⇔一般的なテキスト、の変換が 容易に行えることにあります。

    データを RDB に保存するとき、変数の構造が変化したとしても、 カラムを増やしたり join を行ったりせず、その項目での検索を ある程度あきらめるのであれば、容易かつ高速に、多様な形式の データを保存できます

    class Samples < ActiveRecord::Migration
      def self.up
        create_table :samples do |t|
        t.string “name”
        t.text “description”
        t.text “parms_json” #ここに、詳しいデータを json 化して保存する
      end
      def self.down
        drop_table :samples
      end

    で、ここの「params_json」の値ですが、上の値に関しては、 サーバサイド(Ruby on Rails)で生成した場合と クライアントサイド(Ajax)で生成した場合と、 同じ形式で保存されることが期待されるのですが、 こちら、ちょっと困った「クセ」がそれぞれありました。 そのクセの内容と、対策を共有します。

    0) まずはスタート

    下記のような変数を(ruby の記法)

    hash = {
        :a => “b”, :c => [ [“あ”, “い”, “う”], [“え”, “お”, “か”] ]
    }

    を、

    { “a”:”b”, “c”:[ [“あ”,”い”,”う”], [“え”,”お”,”か”] ] }



    という json にしたい。

    1) Ruby on Rails の場合

    何も考えずに hash.to_json した場合、

    >> hash.to_json => “{\”a\”:\”b\”,\”c\”:[[\”\\u3042\”,\”\\u3044\”,\”\\u3046\”],[\”\\u3048\”,\”\\u304a\”,\”\\u304b\”]]}”

    のように、 unicode_escape されて出力されます。 こちら、escape されて欲しくない場合、下記のような関数を作成し 出力を得ます。

        def json_unescape(str)
          str.gsub(/\\([\\\/]|u[0-9a-fA-F]{4})/) do
            ustr = $1
            if ustr.starts_with?(‘u’)
              [ustr[1..-1].to_i(16)].pack(“U”)
            elsif ustr == ‘\\’
              ‘\\\\’
            else
              ustr
            end
          end
        end

    出力は

    >> json_unescape(hash.to_json) => “{\”a\”:\”b\”,\”c\”:[[\”あ\”,\”い\”,\”う\”],[\”え\”,\”お\”,\”か\”]]}”

    2) jquery-json の場合

    jquery および jquery-json を読み込んだ環境下にて、

    alert(jQuery.toJSON({a:”b”, c:[[“あ”, “い”, “う”], [“え”, “お”, “か”]]}));

    を実行したら、

    {“a”:”b”,”c”:”[[\”あ\”, \”い\”, \”う\”], [\”え\”, \”お\”, \”か\”]]”}

    のように、配列が内部でエスケープされた状態で出力されます。 上記のエスケープを解除したい場合、下記のような処理になります。

    function no_escape_to_json(obj) {
      return jQuery.toJSON(obj).replace(/\\\”/g, “\””).replace(/\”\[/g, “\[“).replace(/\]\”/g, “\]”);
    }

    1), 2) の処理とも、アドホックな対応のため、あまり推奨されないやり方になります。が、もしお困りの方がいればご参考いただきたいな、と。 また、もっと根本的なスマートなやり方がある場合、お教えいただけますと幸いです。

    記事を共有