2016-09-17 225 views
4

我有一個可以嵌套多個註釋的json數組。ELM解析嵌套json

爲例:

[ 
    { 
    "author": "john", 
    "comment" : ".....", 
    "reply": "", 
    }, 
    { 
    "author": "Paul", 
    "comment" : ".....", 
    "reply": [ 
     { 
     "author": "john", 
     "comment" : "nested comment", 
     "reply": [ 
      { 
      "author": "Paul", 
      "comment": "second nested comment" 
      } 
     ] 
     }, 
     { 
     "author": "john", 
     "comment" : "another nested comment", 
     "reply": "" 
     } 
    ] 
    }, 
    { 
    "author": "Dave", 
    "comment" : ".....", 
    "reply": "" 
    }, 
] 

所以它的評論列表,其中每一個註釋可以有回覆無限數量的答覆。 With Json.Decode.list我可以解碼第一級的評論,但是如何檢查是否有一些回覆,然後再解析?

這是我試圖做的簡化版本。我其實試圖解碼reddit的評論。 exemple

+0

你不想有一個解析「再」的心理模型。您希望針對同一個字段使用中間值或不同的解碼器。 看看http://package.elm-lang.org/packages/elm-lang/core/latest/Json-Decode#andThen。它允許根據已經解碼的數據來切換子解碼器。還有'oneOf',允許您解析空字符串(您可以手動將其轉換爲空的回覆列表)或嵌套的回覆。 – pierrebeitz

回答

6

Elm不會讓您創建遞歸記錄類型別名,因此您必須使用Customer的聯合類型。您可能還需要創建用戶的便利功能,以便您可以使用Json.map3

你的例子json有一個奇怪的情況:有時reply是一個空字符串,有時它是一個列表。您需要一個特殊的解碼器來將該字符串轉換爲空列表(假設空列表與此上下文中的空列表同義)。

由於您有遞歸類型,因此需要使用lazy來解碼子註釋以避免運行時錯誤。

import Html exposing (Html, text) 
import Json.Decode as Json exposing (..) 


main : Html msg 
main = 
    text <| toString <| decodeString (list commentDecoder) s 


type Comment 
    = Comment 
     { author : String 
     , comment : String 
     , reply : List Comment 
     } 


newComment : String -> String -> List Comment -> Comment 
newComment author comment reply = 
    Comment 
     { author = author 
     , comment = comment 
     , reply = reply 
     } 


emptyStringToListDecoder : Decoder (List a) 
emptyStringToListDecoder = 
    string 
     |> andThen 
      (\s -> 
       case s of 
        "" -> 
         succeed [] 

        _ -> 
         fail "Expected an empty string" 
      ) 


commentDecoder : Decoder Comment 
commentDecoder = 
    map3 newComment 
     (field "author" string) 
     (field "comment" string) 
     (field "reply" <| 
      oneOf 
       [ emptyStringToListDecoder 
       , list (lazy (\_ -> commentDecoder)) 
       ] 
     ) 


s = 
    """ 
[{ 
    "author": "john", 
    "comment": ".....", 
    "reply": "" 
}, { 
    "author": "Dave", 
    "comment": ".....", 
    "reply": "" 
}, { 
    "author": "Paul", 
    "comment": ".....", 
    "reply": [{ 
    "author": "john", 
    "comment": "nested comment", 
    "reply": [{ 
     "author": "Paul", 
     "comment": "second nested comment", 
     "reply": "" 
    }] 
    }, { 
    "author": "john", 
    "comment": "another nested comment", 
    "reply": "" 
    }] 
}] 
""" 

(您的JSON也以其他方式有點過:有一些額外的逗號列表的最後部分和reply領域之一後失蹤)