Subscribed unsubscribe Subscribe Subscribe

lift-json リファレンス

Scala

参考: JSON Support | Lift Project | Assembla


Scala標準にもjsonパーサとかありますが、lift-jsonのほうが人気。


基礎知識

A central concept in lift-json library is JSON AST (Abstract Syntax Tree) which models the structure of a JSON document as a syntax tree; all features are implemented in terms of AST. It provides a case class for each of the above mentioned JSON primitive and structured type, and provides functions used to transform the AST itself, or to transform the AST between different formats.

図でまとめるとこうなると。



以下ひたすら使い方 & サンプル

import

package objectをimportすることでJValueとかparse,renderなどのメソッドが使えるようになります。

import net.liftweb.json._

Json文字列 -> JsonAST

parse を使う

  val data = """
  {
    "name": "joe",
    "address": {
      "street": "Bulevard",
      "city": "Helsinki"
    },
    "children": [
      {
        "name": "Mary",
        "age": 5
        "birthdate": "2004-09-04T18:06:22Z"
      },
      {
        "name": "Mazy",
        "age": 3
      }
    ]
  }
  """


  val json = parse(data)
  println(json)

  /*
   JObject(List(JField(name,JString(joe)),
                JField(address,JObject(List(JField(street,JString(Bulevard)),
                                            JField(city,JString(Helsinki))))),
                JField(children,
                  JArray(
                    List(JObject(List(JField(name,JString(Mary)),
                                      JField(age,JInt(5)),
                                      JField(birthdate,JString(2004-09-04T18:06:22Z)))),
                         JObject(List(JField(name,JString(Mazy)),
                                      JField(age,JInt(3)))))))))
  */

JsonASTからの値の取り出し

for で子供の名前を取り出してみます。

  for {
    JObject(items) <- json
    item <- items
    JField("children", JArray(children)) <- item
    JObject(child) <- children
    JField("name", JString(name))<- child
  } {
    println(name)
  }
  /*
   Mary
   Mazy
  */

for式便利。でもちょっとがんばってる感ありますね。


XPathのような書き方で取り出すこともできます。

  println(json \\ "children" \ "name")

/* 
JArray(List(JField(name,JString(Mary)), JField(name,JString(Mazy))))
*/

JsonAST -> case class

extract を使うと case class へのマッピングができます。

  case class Person(name: String, address: Address, children: List[Child])
  case class Address(street: String, city: String)
  case class Child(name: String, age: Int, birthdate: Option[java.util.Date])

  println(json.extract[Person])

  /*
   Person(joe,Address(Bulevard,Helsinki),List(Child(Mary,5,Some(Sun Sep 05 03:06:22 JST 2004)), Child(Mazy,3,None)))
  */


2012/01/05 追記
↓こういうこともできるらしい
Lift Json の case class への変換がとても便利な件 - scalaとか・・・

JsonAST -> Json文字列

render で scala.text.Document にしてから pretty or compact

  println(compact(render(json)))

/*
{"name":"joe","address":{"street":"Bulevard","city":"Helsinki"},"children":[{"name":"Mary","age":5,"birthdate":"2004-09-04T18:06:22Z"},{"name":"Mazy","age":3}]}
*/

  println(pretty(render(json)))

/*
{
  "name":"joe",
  "address":{
    "street":"Bulevard",
    "city":"Helsinki"
  },
  "children":[{
    "name":"Mary",
    "age":5,
    "birthdate":"2004-09-04T18:06:22Z"
  },{
    "name":"Mazy",
    "age":3
  }]
}
*/

case class -> Json文字列

Serialization.write を使います。

  import org.scala_tools.time.Imports._

  implicit val format =  DefaultFormats
  println(Serialization.write(
    List(Person("joe" ,Address("Bulevard", "Helsinki"), List(Child("Mary", 5 ,Some(DateTime.now - 5.year toDate)), Child("Mazy", 3, None))),
         Person("john" ,Address("Bulevard", "Helsinki"), List(Child("Mary", 5 ,Some(DateTime.now - 5.year toDate)), Child("Mazy", 3, None))))
  ))
  /*
[{"name":"joe","address":{"street":"Bulevard","city":"Helsinki"},"children":[{"name":"Mary","age":5,"birthdate":"2007-01-03T06:55:16Z"},{"name":"Mazy","age":3}]},
{"name":"john","address":{"street":"Bulevard","city":"Helsinki"},"children":[{"name":"Mary","age":5,"birthdate":"2007-01-03T06:55:16Z"},{"name":"Mazy","age":3}]}]
 */

}

JsonDSLを使ってJsonASTを組み立てる

DSLと言うほどのものではない気がする。
Map -> JValue, Option[A] -> JValue, Int -> JInt などの implicit conversionがいろいろ定義されているのと
あと(String, A)がJsonAssoc[A]ってのに変換されて、そのおかげで "~" というメソッドが使えるようになります。

  import net.liftweb.json.JsonDSL._
  val beatles: JValue = ("Guitar" -> List("John", "George")) ~ ("Bass" -> "Paul") ~ ("Ringo" -> "Drums")
  println(pretty(render(beatles)))
  /*
   {
     "Guitar":["John","George"],
     "Bass":"Paul",
     "Ringo":"Drums"
   }
 */

xml -> Json

net.liftweb.json.Xmlオブジェクトを使うと、xmlJsonの相互変換ができます。

  val xml = {
    <div><name>john</name><age>5</age></div>
  }

  implicit val format =  DefaultFormats
  println(Serialization.write(Xml.toJson(xml)))

/*
{"div":{"name":"john","age":"5"}}
*/

Json -> xml

  println(Xml.toXml(json))

/*
<name>joe</name><address><street>Bulevard</street><city>Helsinki</city></address><children><name>Mary</name><age>5</age>
<birthdate>2004-09-04T18:06:22Z</birthdate></children><children><name>Mazy</name><age>3</age></children>
*/