在Scala中,解析json和映射到对象的最简单方法是什么?

时间:2013-06-17 06:58:39

标签: scala lift lift-json

我正在寻找一个超级简单的方法来获取一个大的JSON片段,这是一个包含大量大对象的长列表,并解析它,然后从每个对象中选择相同的几个值然后映射进入案例类。

我已经很努力地让lift-json(2.5)为我工作了,但是我在干净地处理检查键是否存在时遇到了麻烦,如果是,那么映射整个对象,但如果没有,然后跳过它。

我绝对不理解Lift-JSON的这种语法:

case class Car(make: String, model: String)

...

val parsed = parse(jsonFragment)
val JArray(cars) = parsed / "cars"

val carList = new MutableList[Car]
for (car <- cars) {
    val JString(model) = car / "model"
    val JString(make) = car / "make"

    // i want to check if they both exist here, and if so 
    // then add to carList
    carList += car
}

究竟是什么构造使它看起来像是在赋值运算符左边创建的case类?我在谈论“JString”部分。 它还应该如何应对缺少钥匙的情况?

有人可以向我解释一下这样做的正确方法是什么? 如果我有我正在寻找的嵌套值,我只想跳过整个对象并继续尝试映射下一个。

有没有比Lift-JSON更直接的东西?

会使用 extractOpt 帮助吗?

我看了很多: https://github.com/lift/framework/tree/master/core/json

对我来说仍然不是特别清楚。

帮助非常赞赏!!!!!

3 个答案:

答案 0 :(得分:3)

由于您只想提取某些字段,因此您处于正确的轨道上。 for-comprehension的此修改版本将遍历您的汽车结构,提取品牌和型号,并且只有两个项目存在时才会生成您的案例类:

for{ 
  car <- cars
  model <- (car \ "model").extractOpt[String]
  make <- (car \ "make").extractOpt[String]
} yield Car(make, model)

您可以以相同的方式添加其他必填字段。如果您还想使用可选参数,请说color - 那么您可以在yield部分中调用它,而for comprehension不会将它们取消包装:

for{ 
  car <- cars
  model <- (car \ "model").extractOpt[String]
  make <- (car \ "make").extractOpt[String]
} yield Car(make, model, (car \ "color").extractOpt[String])

在这两种情况下,您都会获得ListCar个案例类别。

答案 1 :(得分:2)

奇怪的外观分配是val声明中使用的模式匹配

当你看到

val JArray(cars) = parsed / "cars"

从解析后的json中提取"cars"个对象的子树,并将结果值与提取器模式 JArrays(cars)进行匹配。
也就是说,该值应该是构造函数JArrays(something)的形式,something绑定到cars变量名称。

它的工作原理与你可能熟悉的案例类很相似,例如Options,例如。

//define a value with a class that can pattern match
val option = Some(1)
//do the matching on val assignment
val Some(number) = option
//use the extracted binding as a variable
println(number)

以下作业完全相同

//pattern match on a JSon String whose inner value is assigned to "model"
val JString(model) = car / "model"
//pattern match on a JSon String whose inner value is assigned to "make"
val JString(make) = car / "make"

参考

JSON类型(例如JValue, JString, JDouble)被定义为net.liftweb.json对象here中的别名。

别名依次指向net.liftweb.json.JsonAST对象中相应的内部案例类,找到here

案例类具有免费的unapply方法,可让您按照上述答案中的说明进行模式匹配

答案 2 :(得分:2)

我认为这应该适合你:

case class UserInfo(
        name: String,
        firstName: Option[String],
        lastName: Option[String],
        smiles: Boolean
        )

val jValue: JValue
val extractedUserInfoClass: Option[UserInfo] = jValue.extractOpt[UserInfo]

val jsonArray: JArray
val listOfUserInfos: List[Option[UserInfo]] = jsonArray.arr.map(_.extractOpt[UserInfo])

我希望jValue拥有smilesname - 否则提取会失败。

我不希望jValue必须有firstNamelastName - 所以我在案例类中写Option[T]