JSON toolkit for Scala (discontinued, see lift-json)
Scala
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
benchmark
lib
project
src
.gitignore
LICENSE.txt
README.md
sbt

README.md

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! NOTE: the development of Literaljson continues as a lift-json module:
!
! See lift-json @
! http://github.com/dpp/liftweb/tree/master
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Literaljson: parsing and formatting utilities for JSON.

DSL rules

  • Primitive types map to JSON primitives.
  • Any seq produces JSON array.

    scala> val json = List(1, 2, 3)

    scala> compact(JsonAST.render(json))

    res0: String = [1,2,3]

  • Tuple2[String, A] produces field.

    scala> val json = ("name" -> "joe")

    scala> compact(JsonAST.render(json))

    res1: String = {"name":"joe"}

  • ~ operator produces object by combining fields.

    scala> val json = ("name" -> "joe") ~ ("age" -> 35)

    scala> compact(JsonAST.render(json))

    res2: String = {"name":"joe","age":35}

  • Any value can be optional. Field and value is completely removed when it doesn't have a value.

    scala> val json = ("name" -> "joe") ~ ("age" -> Some(35))

    scala> compact(JsonAST.render(json))

    res3: String = {"name":"joe","age":35}

    scala> val json = ("name" -> "joe") ~ ("age" -> (None: Option[Int]))

    scala> compact(JsonAST.render(json))

    res4: String = {"name":"joe"}

Example

object JsonExample extends Application {
  import literaljson.JsonAST
  import literaljson.JsonDSL._

  case class Winner(id: Long, numbers: List[Int])
  case class Lotto(id: Long, winningNumbers: List[Int], winners: List[Winner], drawDate: Option[java.util.Date])

  val winners = List(Winner(23, List(2, 45, 34, 23, 3, 5)), Winner(54, List(52, 3, 12, 11, 18, 22)))
  val lotto = Lotto(5, List(2, 45, 34, 23, 7, 5, 3), winners, None)

  val json = 
    ("lotto" ->
      ("lotto-id" -> lotto.id) ~
      ("winning-numbers" -> lotto.winningNumbers) ~
      ("draw-date" -> lotto.drawDate.map(_.toString)) ~
      ("winners" ->
        lotto.winners.map { w =>
          (("winner-id" -> w.id) ~
           ("numbers" -> w.numbers))}))

  println(compact(JsonAST.render(json)))
}

scala> JsonExample
{"lotto":{"lotto-id":5,"winning-numbers":[2,45,34,23,7,5,3],"winners":
[{"winner-id":23,"numbers":[2,45,34,23,3,5]},{"winner-id":54,"numbers":[52,3,12,11,18,22]}]}}

Example produces following pretty printed JSON. Notice that draw-date field is not rendered since its value is None:

scala> pretty(render(JsonExample.json))

{
  "lotto":{
    "lotto-id":5,
    "winning-numbers":[2,45,34,23,7,5,3],
    "winners":[{
      "winner-id":23,
      "numbers":[2,45,34,23,3,5]
    },{
      "winner-id":54,
      "numbers":[52,3,12,11,18,22]
    }]
  }
}

Parsing

Any valid json can be parsed into internal AST format.

scala> import literaljson.JsonParser._
scala> parse(""" { "numbers" : [1, 2, 3, 4] } """)
res0: Either[literaljson.JsonParser.ParseError,literaljson.JsonAST.JValue] = 
      Right(JObject(List(JField(numbers,JArray(List(JInt(1), JInt(2), JInt(3), JInt(4)))))))

Queries

Json AST can be queried using XPath like functions. Following REPL session shows the usage of '\', '\\', 'find', 'filter' and 'values' functions.

The example json is:

{ 
  "person": {
    "name": "Joe",
    "age": 35,
    "spouse": {
      "person": {
        "name": "Marilyn"
        "age": 33
      }
    }
  }
}

Translated to DSL syntax:

scala> import literaljson.JsonAST._
scala> import literaljson.JsonDSL._

scala> val json = 
  ("person" ->
    ("name" -> "Joe") ~
    ("age" -> 35) ~
    ("spouse" -> 
      ("person" -> 
        ("name" -> "Marilyn") ~
        ("age" -> 33)
      )
    )
  )

scala> json \\ "spouse"
res0: literaljson.JsonAST.JValue = JObject(List(JField(spouse,JObject(List(
      JField(person,JObject(List(JField(name,JString(Marilyn)), JField(age,JInt(33))))))))))

scala> compact(render(res0))
res1: String = {"spouse":{"person":{"name":"Marilyn","age":33}}}

scala> compact(render(json \\ "name"))
res2: String = {"name":"Joe","name":"Marilyn"}

scala> compact(render(json \ "person" \ "name"))
res3: String = "name":"Joe"

scala> compact(render(json \ "person" \ "spouse" \ "person" \ "name"))
res4: String = "name":"Marilyn"

scala> json find {
         case JField("name", _) => true
         case _ => false
       }
res5: Option[literaljson.JsonAST.JValue] = Some(JField(name,JString(Joe)))

scala> json filter {
         case JField("name", _) => true
         case _ => false
       }
res6: List[literaljson.JsonAST.JValue] = List(JField(name,JString(Joe)), JField(name,JString(Marilyn)))

scala> json.values
res7: literaljson.JsonAST.JValue#Values = Map(person -> Map(name -> Joe, age -> 35, spouse -> Map(person -> Map(name -> Marilyn, age -> 33))))

Indexed path expressions work too.

scala> val json = parse("""
         { "name": "joe",
           "children": [
             {
               "name": "Mary",
               "age": 5
             },
             {
               "name": "Mazy",
               "age": 3
             }
           ]
         }
       """).right.get

scala> (json \ "children")(0)
res0: literaljson.JsonAST.JValue = JObject(List(JField(name,JString(Mary)), JField(age,JInt(5))))

scala> (json \ "children")(1) \ "name"
res1: literaljson.JsonAST.JValue = JField(name,JString(Mazy))

Compile & package

./sbt compile
./sbt package

Versions

0.1 http://github.com/jonifreeman/literaljson/tree/literaljson-0.1

Kudos