В Elm, как декодировать JSON объект внутри вложенного JSON - PullRequest
0 голосов
/ 15 января 2020

Я использую Elm 0.19.1 с NoRedInk / elm- json -decode-трубопровод / 1.0.0

У меня есть тип самолета, который

type alias Aircraft = {name:String}

Для этого у меня есть следующий декодер:

aircraftDecoder : Json.Decode.Decoder Aircraft        
aircraftDecoder =            
    Json.Decode.succeed Aircraft            
    |> Json.Decode.Pipeline.required "name" Json.Decode.string

К сожалению, декодер жалуется мне, говоря: "BadBody" Проблема с заданным значением: (. ..) " Это потому, что на самом деле моя область интересов, если вокруг нее много шума (из API HATEOAS), например:

{
  "_embedded" : {
    "aircrafts" : [ {
      "name" : "AC01",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/aircrafts/1"
        },
        "aircraft" : {
          "href" : "http://localhost:8080/aircrafts/1"
        }
      }
    }, {
      "name" : "AC01",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/aircrafts/2"
        },
        "aircraft" : {
          "href" : "http://localhost:8080/aircrafts/2"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/aircrafts{?page,size,sort}",
      "templated" : true
    },
    "profile" : {
      "href" : "http://localhost:8080/profile/aircrafts"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 4,
    "totalPages" : 1,
    "number" : 0
  }
}

Как я могу изменить код, и продолжать использовать конвейер , чтобы декодер не терялся из-за всего этого шума?

Я что-то слышал об использовании Json .Decode.at, но документация недостаточно хороша, чтобы позвольте мне получить правильный код.

Ответы [ 2 ]

4 голосов
/ 15 января 2020

Насколько я могу судить, проблема в том, что:

  1. в данный момент, ваш декодер может быть пригоден для декодирования одного Aircraft
  2. однако, ваш JSON имеет список Aircraft s
  3. . Кроме того, ваш декодер не знает, где в JSON он может найти Aircraft s

И вы знаете, для Вяза Aircraft и List Aircraft - это совершенно разные ритмы (как и должно быть). В любом случае, решение будет двухэтапным:

  1. Указание декодеру, где в структуре JSON находятся Aircraft s
  2. Разобрать List Aircraft вместо одного Aircraft

После вашего кода и импорта at и list из Json.Decode код может выглядеть следующим образом:

listAircraftDecoder : Json.Decode.Decoder List Aircraft 
listAircraftDecoder =
    at ["_embedded", "aircrafts"] (list aircraftDecoder)

This означает, что теперь мы нацелены на список Aircraft с, и этот список является массивом в JSON. Начиная с JSON root, возьмите свойство "_embedded" и внутри него свойство "aircrafts". Это массив, и Elm list знает, как с ним обращаться.

Наконец, нам просто нужно сказать Elm list, чтобы передать каждый элемент массива JSON в специфицированный c декодер - ваш aircraftDecoder в нашем случае.

Имеет ли это смысл?

1 голос
/ 15 января 2020

Должно работать следующее:

aircraftNameDecoder : Json.Decode.Decoder String
aircraftNameDecoder =
    Json.Decode.map (Maybe.withDefault "" << List.head) <|
        Json.Decode.at [ "_embedded", "aircrafts" ] <|
            Json.Decode.list (Json.Decode.field "name" Json.Decode.string)


aircraftDecoder : Json.Decode.Decoder Aircraft
aircraftDecoder =
    Json.Decode.succeed Aircraft
        |> Json.Decode.Pipeline.custom aircraftNameDecoder

И, пожалуйста, смотрите вяз / json для получения дополнительной документации по Json.Decode.at.

...