【问题标题】:Parsing JSON with LINQ-style queries in Scala在 Scala 中使用 LINQ 样式的查询解析 JSON
【发布时间】:2014-03-25 13:47:44
【问题描述】:

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

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

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

案例类状态(成功:布尔,代码:整数,消息:字符串) val json = parse(text) // text 是上面的 JSON val statusList = for { JObject(obj)

这有意义吗?

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

我可以使用headOption 轻松地将List[Status] 转换为Option[Status],但我想直接获得Option[Status]

我可以用 json4s 解析 JSON 以获得 Option[Status] 先不获得 List[Status] 吗?

【问题讨论】:

  • 如果您可以“直接获取Option[Status]”,哪些特别不适用于headOption?我不明白你的问题。
  • headOption 确实有效。先得到List 然后再转换成Option 看起来很尴尬。
  • 在代码格式或性能方面有问题?
  • 这里我不太关心性能。

标签: json scala json4s


【解决方案1】:

您可以将类似 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)

【讨论】:

    【解决方案2】:

    你可以使用json4s内置的extraction。在你的情况下extractOpt 而不是extract

    【讨论】:

      【解决方案3】:

      for-comprehension 的替代方案是以下类,它隐含地将 unpack 方法添加到 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)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-22
        • 1970-01-01
        • 1970-01-01
        • 2014-03-11
        • 2012-05-11
        • 1970-01-01
        相关资源
        最近更新 更多