Yes, you can write a general purpose decoder. You can first determine the type of union that contains all the possible Json types:
type JsVal = JsString String | JsInt Int | JsFloat Float | JsArray (List JsVal) | JsObject (Dict String JsVal) | JsNull
And now you can use Json.Decode.oneOf to try all the features.
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.lazy required for the JsArray and JsObject because they are defined recursively.
This structure should process everything that you throw on it, and decide the rest of your program to decide what to do with such a flexible type.
Edit
As @Tosh pointed out, this decoder can be cleared using map instead of andThen followed by succeed :
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 ]
Chad gilbert
source share