2012年10月14日日曜日

[Scala] JSON の扱い

Scala には 標準で JSON を扱うためのクラスが用意されている。
sjson というライブラリもあるが、 まずは Scala 標準の JSON を使ってみる。


パース

scala.util.parsing.json.JSON クラスを使ってテキストの JSON をパースする。
  • JSON.parseRaw
    パース結果として、Option[JSONType] が返る。
  • JSON.parseFull
    パース結果として、Option[Any] が返る。
他に JSON.parse というメソッドもあるが、Scala 2.8.0 以降は Deprecated されて parseRaw または parseFull を使うようになっている。

まずは、parseRaw から。
  val text = """{ "x":10, "y":20 }""";
  val result : Option[JSONType] = JSON.parseRaw(text);
  val jo : JSONObject = result.get.asInstanceOf[JSONObject];
  val map : Map[String, Option[Any]] 
      = jo.obj.asInstanceOf[Map[String, Option[Any]]];

  println (map.get("x").get);

--------------------
10.0
Option[JSONType].get で取得できる JSONType は、JSON が オブジェクトの時には JSONObject、配列の時には JSONArray になる。

JSONObject からは obj メンバー でオブジェクトの属性名と値からなる Map を取り出すことができる。
JSONArray の場合は Map の代わりに Array が取得できる。

実際に必要な値を取り出すために、JSONType から取得するので少し手数がかかるが、一方 JSONType のままできることもさしてないのであまり parseRaw を使う理由はなさそう。

次に parseFull 。
  val text = """{ "x":10, "y":20 }""";
  val result : Option[Any] = JSON.parseFull(text);
  val map : Map[String, Option[Any]] 
      = result.get.asInstanceOf[Map[String, Option[Any]]];
  println (map.get("x").get);

--------------------
10.0
parseFullでは Option[Any].get で Map か Array が直接取り出せるので、こちらの方が手数は少ない。
あえて parseRaw を使う理由もないので、普通は parseFull を使えばいい。


シリアライズ

シリアライズは JSONObject を作成して toString で文字列化する。
  val map = Map(
      "x" -> 1, 
      "y" -> 2.0,
      "m" -> JSONObject(Map("z" -> 10)),
      "a" -> JSONArray(List(1,2,3)));
  val obj = JSONObject(map);
  println(obj.toString())

--------------------
{"x" : 1, "y" : 2.0, "m" : {"z" : 10}, "a" : [1, 2, 3]}
JSONObject のもとになる Map が 属性値として オブジェクト( Map ) や 配列( List ) を含む場合は、上の例のように JSONObject や JSONArray にしておく必要がある。
Map や List のままにすると次のようにいささか残念な出力ができてしまう。
  val map2 = Map(
      "x" -> 1, 
      "y" -> 2.0,
      "m" -> Map("z" -> 10),
      "a" -> List(1,2,3));
  val obj2 = JSONObject(map2);
  println(obj2.toString())

--------------------      
{"x" : 1, "y" : 2.0, "m" : Map(z -> 10), "a" : List(1, 2, 3)}
いちいち、JSONObject や JSONArray にしなくても JSONObject を正しく構築してほしいところなのだが、 そこを譲ったとしても「正しくない」JSON 文字列が平然と出力されてしまうところがいただけない。
変換忘れ防止の意味でも エラーにするべきなのではないかと思う。

こういうあたりが、Scalaの標準JSONライブラリがいまいちという評価になっているのではないのだろうか。

0 件のコメント:

コメントを投稿