Разобрать массив JSON с помощью Scala Argonaut

Я использую 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]?

person Gilbert    schedule 18.03.2014    source источник
comment
Что вы пробовали? Можете ли вы показать свой код?   -  person serejja    schedule 18.03.2014
comment
Прежде всего, ваш JSON недействителен. Может из-за этого ошибки? Или какой у тебя план? См. jsonlint.com для проверки JSON.   -  person Themerius    schedule 18.03.2014


Ответы (3)


Самый простой способ сделать это — определить кодек для MyType. Затем компилятор с радостью создаст декодер для List[MyType] и т. д. Я буду использовать здесь простой класс (не case-класс), чтобы было понятно, что происходит:

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 принимает два списка параметров. Первый имеет два параметра, которые позволяют вам сказать, как создать экземпляр MyType из Tuple3 и наоборот. Второй список параметров позволяет указать имена полей.

Теперь вы можете просто написать что-то вроде следующего (если json ваша строка):

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

И вы сделали.

person Travis Brown    schedule 27.03.2014
comment
Я бы предложил использовать casecodec вместо неявного кодека def MyTypeCodec = casecodec3(MyType.apply, MyType.unapply)(name, type, size) - person Roman Zykov; 12.04.2018

Поскольку вам не нужно кодировать и вы смотрите только на декодирование, вы можете сделать, как предложил Трэвис, но внедрив другое неявное: 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)
person Calahad    schedule 09.02.2016

Предполагая, что MyType является классом case, также работает следующее:

case class MyType(name: String, type: String, size: Int)

object MyType {
    implicit val createCodecJson: CodecJson[MyType] = CodecJson.casecodec3(apply, unapply)(
        "name",
        "type",
        "size"
    )
}
person smac89    schedule 02.09.2020