2017-12-21 27 views
1

와 느릅 나무로 객체 :디코딩 다형성 JSON 내 JSON이 비슷합니다 andThen

{ "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

Elm 0.17 이하를 대상으로 책이 작성된 것 같습니다. 엘름 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" 값을 사용합니다.

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

당신은 required'가와'custom'이 Json.Decode.Pipeline''소속'언급하는 것을 잊었다 : 우리는 느릅 나무의 field 디코더를 사용하여 Decoder Int 값을 가져 오는 후 (느릅 나무 0.18로 파이프 라인 구문) andThen 사용할 수 있습니다 . 핵심 패키지를 고수하고 싶다면 대신'map3'과'field'를 사용할 수 있습니다. –

+0

Chad와 Chris에게 솔루션과 유용한 설명을 해주셔서 감사합니다. 너무 많은 pre-0.18 튜토리얼을 발견하고,'Decode.Pipeline.custom'에 대한 새로운 설명조차도 도움이되지 않았다는 것을 알게되었습니다. 귀하의 설명은 훨씬 더 많은 도움이되었습니다. –