Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using lift-json, is there an easy way to extract and traverse a list?

I think I may be missing something fundamental from the list-json xpath architecture. The smoothest way I've been able to extract and traverse a list is shown below. Can someone please show me a better technique:

class Example {

    @Test
    def traverseJsonArray() {

        def myOperation(kid:JObject) = println("kid="+kid)

        val json = JsonParser.parse("""
            {   "kids":[
                {"name":"bob","age":3},
                {"name":"angie","age":5},
            ]}
        """)

        val list = ( json \\ "kids" ).children(0).children
        for ( kid <- list ) myOperation(kid.asInstanceOf[JObject])

    }

}
like image 624
Fred Haslam Avatar asked Feb 22 '11 03:02

Fred Haslam


1 Answers

If at all possible you should upgrade to Lift JSON 2.3-M1 (http://www.scala-tools.org/repo-releases/net/liftweb/lift-json_2.8.1/2.3-M1/). It contains two important improvements, the other affecting the path expressions.

With 2.3 the path expressions never return JFields, instead the values of JFields are returned directly. After that your example would look like:

val list = (json \ "kids").children
for ( kid <- list ) myOperation(kid.asInstanceOf[JObject])

Lift JSON provides several styles to parse values from JSON: path expressions, query comprehensions and case class extractions. It is possible to mix and match these styles and to get the best results we often do. For completeness sake I'll give you some variations of the above example to get a better intuition of these different styles.

// Collect all JObjects from 'kids' array and iterate
val JArray(kids) = json \ "kids"
kids collect { case kid: JObject => kid } foreach myOperation

// Yield the JObjects from 'kids' array and iterate over yielded list
(for (kid@JObject(_) <- json \ "kids") yield kid) foreach myOperation

// Extract the values of 'kids' array as JObjects
implicit val formats = DefaultFormats
(json \ "kids").extract[List[JObject]] foreach myOperation

// Extract the values of 'kids' array as case classes
case class Kid(name: String, age: Int)

(json \ "kids").extract[List[Kid]] foreach println

// Query the JSON with a query comprehension
val ks = for { 
  JArray(kids) <- json
  kid@JObject(_) <- kids
} yield kid 
ks foreach myOperation
like image 114
Joni Avatar answered Sep 22 '22 23:09

Joni