1

假设我需要解析一个 JSON(见下文)。

{
  成功:真
  状态码:0
  状态消息:“好的”
  payload { ... } // 一些实际数据
}

首先,我正在解析“状态”字段以获取case class Status(见下文)的实例

案例类状态(成功:布尔,代码:整数,消息:字符串)

val json = parse(text) // text 是上面的 JSON

val statusList = for {
    JObject(obj) <- json
    JField("成功", JBool(成功)) <- obj
    JField("code", JInt(code)) <- obj
    JField("消息", JString(消息)) <- obj
  } 产生状态(成功,代码,消息)

是否有意义 ?

的类型statusListList[Status]。它包含一个Status项目。如果解析失败,statusList则为空。我喜欢它,因为我想要Option[Status]而不是List[Status]

我可以很容易地转换List[Status]Option[Status]withheadOption但我想Option[Status]直接得到。

我可以解析 JSONjson4s以获取 Option[Status] 而无需先获取List[Status]吗?

4

3 回答 3

2

您可以使用 json4s 内置提取。在你的情况下extractOpt,而不是extract.

于 2014-03-25T14:21:53.190 回答
2

您可以使用类似 XPath 的函数,以及toOption

val statusOpt = for {
    JBool(success) <- (json / "success").toOption
    JInt(code) <- (json / "code").toOption
    JString(message) <- (json / "message").toOption
  } yield Status(success, code, message)
于 2014-03-25T14:34:09.333 回答
1

理解的替代方法是以下类,它隐含地将unpack方法添加到 a JValue

case class UnpackableJValue(jv: JValue) {

  import scala.util.Try

  def unpack[A](f: JValue => A): A = f(jv)

  def unpackList[A](f: JValue => A): List[A] = jv match {
    case JArray(values) => values map f
    case _ => List.empty
  }

  def unpackOpt[A](f: JValue => A): Option[A] = Try(f(jv)).toOption

}

object UnpackableJValue {
  implicit def jvalue2unpackable(jv: JValue) = UnpackableJValue(jv)
}

unpack方法接收一个函数,该函数负责从JValue.

import UnpackableJValue._

implicit val formats = DefaultFormats

case class Status(success: Boolean, code: Int, message: String)

val json = parse(
  """
    |{
    |  "success": true,
    |  "statusCode": 0,
    |  "statusMessage": "Ok",
    |  "payload": { }
    |}
  """.stripMargin)

val res = json.unpack[Status] { v =>
  val success = (v \ "success").extract[Boolean]
  val code = (v \ "statusCode").extract[Int]
  val message = (v \ "statusMessage").extract[String]

  Status(success, code, message)
}

println(res)
// Status(true,0,Ok)
于 2014-03-29T22:53:48.780 回答