2016-11-27 5 views
7

私はElmと協力して、私が取り組んでいるRest APIを使っていくつかのフロントエンドプロトタイプを作成し始めました。一般に、キーと値の型はよく知られているので、APIはデコードできる「合理的な」データ構造を返しますが、いくつかのリソース型は未定義のjsonを持つちょうどのエントリを返します。未知のjson構造を解読するElm

これまでに読んだことはすべて、デコードしているデータの構造を知っていると思われますが、プレーンなjsではキーをループして型を反映するのは比較的簡単です。実行時に処理されます。私はElmのこの種のデータを扱うための明確な道筋はまだ見ていません。

例えば、

{ 
    "name":"foo", 
    "data": { 
    "bar": [{"baz":123}, "quux"] 
    }, 
    ... 
} 
私は具体的に

function go(obj) 
    for key in keys(foo) 
     if foo[key] is an object 
      go(foo[k]) 
     else if foo[key] is an array 
      map(go, foo[k]) 
     ... 

に似た何かでdataエントリの値を解析することはできているかどうかを知りたいのですが

  1. Elmで不明な、おそらく深くネストされた異種のjsonデータを扱うことは現在可能ですか?
  2. もしそうなら、著者がこのようなデータをどのようにデコードするのかについて、私はキーコンセプトや高度な直感を教えていただけますか?
+0

私はそれが「Elm-ではありません怖いですあなたが知らない構造を受け取るように "好きです。 Elmでは、オブジェクトには常に特定のプロパティが含まれていると予想され、Elmは実行時に、そのオブジェクトに存在するすべてのプロパティが存在するかどうかをチェックします。 –

答えて

6

はい、汎用デコーダを作成することは可能です。あなたは最初にすべての可能なJSON型を保持しているユニオン型を定義することができます。

type JsVal 
    = JsString String 
    | JsInt Int 
    | JsFloat Float 
    | JsArray (List JsVal) 
    | JsObject (Dict String JsVal) 
    | JsNull 

そして今、あなたはすべての可能性を試してJson.Decode.oneOfを使用することができます。彼らは再帰的に定義されているので

import Json.Decode as D exposing (Decoder) 
import Dict exposing (Dict) 

jsValDecoder : Decoder JsVal 
jsValDecoder = 
    D.oneOf 
    [ D.string |> D.andThen (D.succeed << JsString) 
    , D.int |> D.andThen (D.succeed << JsInt) 
    , D.float |> D.andThen (D.succeed << JsFloat) 
    , D.list (D.lazy (\_ -> jsValDecoder)) |> D.andThen (D.succeed << JsArray) 
    , D.dict (D.lazy (\_ -> jsValDecoder)) |> D.andThen (D.succeed << JsObject) 
    , D.null JsNull 
    ] 

Json.Decode.lazyJsArrayJsObjectコンストラクタのために必要です。

この構造体は、あなたが投げるものを処理する必要があります。このような柔軟な型で何をするかは、プログラムの残りの部分で決まります。

編集

@Toshが指摘したように、このデコーダは、代わりにsucceed続いandThenmapを使用してクリーンアップすることができます。

jsValDecoder : Decoder JsVal 
jsValDecoder = 
    D.oneOf 
    [ D.map JsString D.string 
    , D.map JsInt D.int 
    , D.map JsFloat D.float 
    , D.list (D.lazy (\_ -> jsValDecoder)) |> D.map JsArray 
    , D.dict (D.lazy (\_ -> jsValDecoder)) |> D.map JsObject 
    , D.null JsNull 
    ] 
+2

フォームを使用できるとコメントしたいとします。 'D.map JsString D.string'。少なくとも私のために読むのが少し楽になりました。 – Tosh

+0

ありがとう、@トッシュ!良い点は、「成功」モナド結合は、単純な 'map'も同様にうまくいくはずです。 –

関連する問題