抽象从Scala中的JSON中提取数据

时间:2015-02-16 20:16:04

标签: json scala

我正在寻找一个好的抽象来从JSON中提取数据(我现在正在使用json4s)。

假设我有一个案例类A和JSON格式的数据。

case class A(a1: String, a2: String, a3: String)

{"a1":"xxx", "a2": "yyy", "a3": "zzz"}

我需要一个函数来提取JSON数据并使用以下数据返回A

val a: JValue => A = ...

我不想从头开始编写函数a。我宁愿从原始函数中编译

例如,我可以编写一个基本函数来按字段名称提取字符串:

val str: (String, JValue) => String = {(fieldName, jval) => ... }

现在我想从a: JValue => A 撰写函数str。它有意义吗?

2 个答案:

答案 0 :(得分:2)

考虑使用Play-JSON,其中包含composable“读取”对象。如果您曾经使用过ReactiveMongo,它可以以相同的方式使用。与此处的一些较旧的帖子相反,它可以单独使用,而不需要Play的大部分内容。

它使用常见的“隐式翻译”(我的术语)成语。我发现我最喜欢使用它的反序列化模式并没有在文档中突出显示 - 他们所支持的模式很难做到,恕我直言。我大量使用了.as和.asOpt,这些都记录在上面的第一个链接页面的“Using JsValue.as/asOpt”小部分中。反序列化JSON对象时,可以说类似

val person:Person = (someParsedJsonObject \ "aPerson").as[Person]

只要你在范围内有一个隐含的Reads [Person],一切正常。所有原始类型和许多集合类型都有内置的Reads。在许多情况下,将Reads and Writes隐式对象放在伴侣对象中是有意义的,例如Person。

我认为json4s有类似功能,但我可能错了。

答案 1 :(得分:1)

Argonaut是功能齐全的Scala库。

它允许encode/decode case classes(JSON编解码器)。

import argonaut._, Argonaut._

case class Person(name: String, age: Int)

implicit def PersonDecodeJson: DecodeJson[Person]
  jdecode2L(Person.apply)("name", "age")
  // Codec for Person case class from JSON of form
  // { "name": "string", "age": 1 }

它还提供JSON光标(镜头/单片眼镜)进行自定义解析。

implicit def PersonDecodeJson: DecodeJson[Person] =
  DecodeJson(c => for {
    name <- (c --\ "_name").as[String]
    age <- (c --\ "_age").as[String].map(_.toInt)
  } yield Person(name, age))
  // Decode Person from a JSON with property names different
  // from those of the case class, and age passed as string:
  // { "_name": "string", "age": "10" }

解析结果由DecodeResult类型表示,可以组成(.map.flatMap)并处理错误情况。