使用andThen将多态JSON对象解码为elm

时间:2017-12-21 20:15:32

标签: json elm

我的JSON看起来与此相似:

{ "items" : 
  [ { "type" : 0, "order": 10, "content": { "a" : 10,  "b" : "description", ... } }
  , { "type" : 1, "order": 11, "content": { "a" : 11,  "b" : "same key, but different use", ... } }
  , { "type" : 2, "order": 12, "content": { "c": "totally different fields", ... } }
   ...
  ] 
}

我希望使用type值来决定解码时要创建的联合类型。所以,我在elm中定义了以上所有的别名类型和解码器:

import Json.Decode exposing (..)
import Json.Decode.Pipeline exposing (..)

type alias Type0Content = { a : Int, b : String }
type alias Type1Content = { a : Int, b2 : String }
type alias Type2Content = { c : String }
type Content = Type0 Type0Content | Type1 Type1Content | Type2 Type2Content
type alias Item = { order : Int, type : Int, content: Content }

decode0 = succeed Type0Content
    |> requiredAt ["content", "a"] int
    |> requiredAt ["content", "b"] string
decode1 = succeed Type1Content
    |> requiredAt ["content", "a"] int
    |> requiredAt ["content", "b"] string
decode2 = succeed Type2Content
    |> requiredAt ["content", "c"] string
decodeContentByType hint =
    case hint of
        0 -> Type0 decode0
        1 -> Type1 decode1
        2 -> Type2 decode2
        _ -> fail "unknown type"
decodeItem = succeed Item
    |> required "order" int
    |> required "type" int `andThen` decodeContentByType

无法根据需要获取最后两个要进行交互的功能。 我已经通过Brian Thicks阅读了json-survival-kit的第33页,但这并没有让我走上正轨。

任何建议和讲座都表示赞赏!

1 个答案:

答案 0 :(得分:1)

看起来这本书的目标是榆木0.17或以下。在Elm 0.18中,backtick syntax was removed。您还需要为type使用不同的字段名称,因为它是保留字,因此我将其重命名为type_

某些注释可能有助于缩小错误范围。让我们注释decodeContentByType,因为现在,分支没有返回相同的类型。三个成功的值应该是将解码器映射到预期的Content构造函数:

decodeContentByType : Int -> Decoder Content
decodeContentByType hint =
    case hint of
        0 -> map Type0 decode0
        1 -> map Type1 decode1
        2 -> map Type2 decode2
        _ -> fail "unknown type"

现在,解决decodeItem功能。我们需要三个字段来满足Item构造函数。第二个字段是类型,可以通过required "type" int获得,但第三个字段依赖于"type"值来推导出正确的构造函数。在使用Elm的andThen解码器获取Decoder Int值后,我们可以使用field(使用Elm 0.18的管道语法):

decodeItem : Decoder Item
decodeItem = succeed Item
    |> required "order" int
    |> required "type" int
    |> custom (field "type" int |> andThen decodeContentByType)