Scala で JSON を扱う

lift-json 使ってます。 build.sbt

libraryDependencies ++= Seq(
  "net.liftweb" % "lift-json_2.9.2" % "2.5-M1"
)

 
サンプルの JSON 文字列

import net.liftweb.json._

val data = """
{
  "id": "1000",
  "test": "hoge",
  "user": "Ajido"
  "data": {
    "key":  "value"
  }
}
"""

 
パースするときはまずオブジェクト化

val jsonObj = parse(data)
println(pretty(render(jsonObj)))

// {
//   "id":"1000",
//   "test":"hoge",
//   "user":"Ajido",
//   "data":{
//     "key":"value"
//   }
// }

 
オブジェクトを case class に変換する
JavaScript ライクにアクセスできるようになって、同時にバリデートもされる。超便利

val jsonObj = parse(data)

case class Message(id: String, user: String, data: Data)
case class Data(key: String)

implicit val formats = DefaultFormats
val msg = jsonObj.extract[Message]

println(msg)
println(msg.id)
println(msg.data.key)

// Message(1000, Ajido, Data(value))
// 1000
// value

 
render が JSON.stringify で、pretty は PrettyPrint

val jsonObj = parse(data)
implicit val formats = DefaultFormats

println(pretty(render(jsonObj)))
// {
//   "id":"1000",
//   "test":"hoge",
//   "user":"Ajido",
//   "data":{
//     "key":"value"
//   }
// }

 
ワンステップで JSON 構築して文字列化
シンプルな application/json レスポンスを返したいときなどに

val jsonObj = parse(data)
implicit val formats = DefaultFormats

case class Message(id: String, user: String, data: Data)
case class Log(id: String, user: String, data: List[Data])
case class Data(key: String)

println(Serialization.write(Message("1000", "Ajido", Data("value"))))
// {"id":"1000","user":"Ajido","data":{"key":"value"}}

空配列で初期化するときは Nil

println(Serialization.write(Log("1000", "Ajido", Nil)))
// {"id":"1000","user":"Ajido","data":[]}

オブジェクト配列は List

println(Serialization.write(Log("1000", "Ajido", List(Data("value")))))
// {"id":"1000","user":"Ajido","data":[{"key":"value"}]}

 
JSON データの変換
例: test フィールドを削除して、user フィールドを大文字に変換

val jsonObj = parse(data)

println(compact(render(jsonObj transform {
  case JField("user", JString(s)) => JField("USER", JString(s.toUpperCase))
  case JField("test", JString(s)) => JNothing
})))

// {"id":"1000","USER":"AJIDO","data":{"key":"value"}}

 
JSON データのフィルタリング。複雑なフィルタなら case class に変換する前にこちらを通す
例: id, user フィールド以外を削除

val jsonObj = parse(data)

println(compact(render(jsonObj filter {
  case JField("id", JString(s)) => true
  case JField("user", JString(s)) => true
  case _ => false
} reduce ((a, b) => a ++ b))))

// {"id":"1000","user":"Ajido"}

 
二次元データに変換。クエリ化するときに使うかも

val jsonObj = parse(data)
println(Extraction.flatten(jsonObj))

// Map(
//   .id -> "1000",
//   .test -> "hoge",
//   .user -> "Ajido",
//   .data.key -> "value"
// )

 
Key が固定値ではない JSON を扱う

val data = """
{
  "data": {
    "Tue Oct  2 01:16:28 JST 2012" : { "key" : "value1" },
    "Tue Oct  2 01:16:30 JST 2012" : { "key" : "value2" }
  }
}
"""

固定値でない箇所に JObject を指定した case class を利用してパース

case class Data(data: JObject)
case class Value(key: String)

implicit val formats = DefaultFormats
val jsonObj = parse(data).extract[Data]

println(Serialization.write(jsonObj))
// {"data":{"Tue Oct  2 01:16:28 JST 2012":{"key":"value1"},"Tue Oct  2 01:16:30 JST 2012":{"key":"value2"}}}

値の取得

println(jsonObj.data.values("Tue Oct  2 01:16:28 JST 2012"))
// Map(key -> value1)

KeyValue リストの走査

jsonObj.data.values foreach {
  case (s: String, m: Map[_, _]) => println(s, m)
}
// (Tue Oct  2 01:16:28 JST 2012,Map(key -> value1))
// (Tue Oct  2 01:16:30 JST 2012,Map(key -> value2))

Key の一覧取得

println(jsonObj.data.values.keys)
Set(Tue Oct  2 01:16:28 JST 2012, Tue Oct  2 01:16:30 JST 2012)

 
Key が固定値ではない JSON の構築

case class Data(data: JObject)
case class Value(key: String)

implicit val formats = DefaultFormats

var src = collection.mutable.ListBuffer[JField]()
src += JField("Tue Oct  2 01:16:28 JST 2012", Extraction.decompose(Value("value1")))
src += JField("Tue Oct  2 01:16:30 JST 2012", Extraction.decompose(Value("value2")))

println(Serialization.writePretty(Data(JObject(src.result))))
// {
//   "data":{
//     "Tue Oct  2 01:16:28 JST 2012":{
//       "key":"value1"
//     },
//     "Tue Oct  2 01:16:30 JST 2012":{
//       "key":"value2"
//     }
//   }
// }
広告を非表示にする