【问题标题】:Parse JSON array using Scala Argonaut使用 Scala Argonaut 解析 JSON 数组
【发布时间】:2014-03-18 15:32:51
【问题描述】:

我正在使用 Scala 和 Argonaut,试图解析以下 JSON:

[
    {
        "name": "apple",
        "type": "fruit",
        "size": 3
    },
    {
        "name": "jam",
        "type": "condiment",
        "size": 5
    },
    {
        "name": "beef",
        "type": "meat",
        "size": 1
    }
]

并且努力研究如何迭代并将值提取到List[MyType] 中,其中MyType 将具有名称、类型和大小属性。

我将很快发布更具体的代码(我已经尝试了很多东西),但基本上我希望了解光标的工作原理,以及如何遍历数组等。我尝试使用 \\ (downArray) 来移动到数组的头部,然后:->- 遍历数组,然后--\ (downField) 不可用(至少IntelliJ 不这么认为)。 所以问题是我该怎么做:

  • 导航到数组
  • 遍历数组(知道什么时候完成)
  • 为每个字段提取字符串、整数等值 - jdecode[String]? as[String]?

【问题讨论】:

  • 你尝试了什么?你能展示你的代码吗?
  • 首先,你的 JSON 无效。也许这会导致错误?或者你的计划是什么?有关 JSON 验证,请参阅 jsonlint.com

标签: json scala argonaut


【解决方案1】:

最简单的方法是为MyType 定义一个编解码器。然后编译器会很高兴地为List[MyType] 等构造一个解码器。我将在这里使用一个普通类(不是案例类)来说明发生了什么:

class MyType(val name: String, val tpe: String, val size: Int)

import argonaut._, Argonaut._

implicit def MyTypeCodec: CodecJson[MyType] = codec3(
  (name: String, tpe: String, size: Int) => new MyType(name, tpe, size),
  (myType: MyType) => (myType.name, myType.tpe, myType.size)
)("name", "type", "size")

codec3 有两个参数列表。第一个有两个参数,允许您告诉如何从Tuple3 创建MyType 的实例,反之亦然。第二个参数列表让您指定字段的名称。

现在您可以编写如下内容(如果 json 是您的字符串):

Parse.decodeValidation[List[MyType]](json)

你已经完成了。

【讨论】:

  • 我建议使用 casecodec 而不是 codec implicit def MyTypeCodec = casecodec3(MyType.apply, MyType.unapply)("name", "type", "size")
【解决方案2】:

由于您不需要编码并且只查看解码,您可以按照 Travis 的建议进行操作,但通过实现另一个隐式:MyTypeDecodeJson

implicit def MyTypeDecodeJson: DecodeJson[MyType] = DecodeJson(
    raw => for {
    name     <- raw.get[String]("name")
    type     <- raw.get[String]("type")
    size     <- raw.get[Int]("size")
  } yield MyType(name, type, size))

然后解析你的列表:

Parse.decodeValidation[List[MyType]](jsonString)

【讨论】:

    【解决方案3】:

    假设MyType 是一个案例类,以下也可以:

    case class MyType(name: String, type: String, size: Int)
    
    object MyType {
        implicit val createCodecJson: CodecJson[MyType] = CodecJson.casecodec3(apply, unapply)(
            "name",
            "type",
            "size"
        )
    }
    

    【讨论】:

      最近更新 更多