Skip to content

Instantly share code, notes, and snippets.

@laszlopandy
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save laszlopandy/5817cbb5997830125b9c to your computer and use it in GitHub Desktop.
Save laszlopandy/5817cbb5997830125b9c to your computer and use it in GitHub Desktop.
Laszlo's JSON parsing proposal

Laszlo's JSON parsing proposal

The following functions should be available in Elm's standard library:

module Json where

parse : String -> Maybe JsonValue
getProp : String -> JsonValue -> Maybe JsonValue
toString : JsonValue -> Maybe String
toInt : JsonValue -> Maybe Int
toFloat : JsonValue -> Maybe Float
toBool : JsonValue -> Maybe Bool
isNull : JsonValue -> Bool
arrayMap : (JsonValue -> Maybe a) -> JsonValue -> Maybe [a]
module Maybe where

getDefault : a -> Maybe a -> a
both : (a -> b -> c) -> Maybe a -> Maybe b -> Maybe c
andThen : Maybe a -> (a -> Maybe b) -> Maybe b

Example usage

Here is an example of manual JSON parsing in Elm 0.12 (author David Biro):

stringToResult = jsonToResult << stringToJson

stringToJson : String -> Json.Value
stringToJson str = 
	case Json.fromString str of
		Just value -> value
		Nothing    -> Json.String ""

jsonToResult : Json.Value -> [SearchResultEntry]
jsonToResult value =
	case value of
		Json.Object dict ->
			case Dict.get "items" dict of
				Just (Json.Array items) -> justs (map itemJsonToEntry items)
				Nothing -> []
		otherwise -> []

itemJsonToEntry : Json.Value -> Maybe SearchResultEntry
itemJsonToEntry item =
	case item of
		Json.Object dict ->
			case Dict.get "link" dict of
				Just (Json.String url) ->
					case Dict.get "image" dict of
						Just imageJson -> Just (imageJsonToEntry url imageJson)
						otherwise -> Nothing
				otherwise -> Nothing
		otherwise -> Nothing

imageJsonToEntry : String -> Json.Value -> SearchResultEntry
imageJsonToEntry url imageJson =
		{ url             = url
		, width           = getIntPropOrElse    0  "width"           imageJson
		, height          = getIntPropOrElse    0  "height"          imageJson
		, thumbnailUrl    = getStringPropOrElse "" "thumbnailLink"   imageJson
		, thumbnailWidth  = getIntPropOrElse    0  "thumbnailWidth"  imageJson
		, thumbnailHeight = getIntPropOrElse    0  "thumbnailHeight" imageJson
		}

With the proposed JSON API, the example can be simplified to:

stringToResult : String -> [SearchResultEntry]
stringToResult str =
	Json.parse str
		`Maybe.andThen` Json.getProp "items"
		`Maybe.andThen` Json.arrayMap itemJsonToEntry
		|> Maybe.getDefault []

itemJsonToEntry : Json.JsonValue -> Maybe SearchResultEntry
itemJsonToEntry item =
	let url = Json.getProp "link" item |> Json.toString
		image = Json.getProp "image" item
	in
		Maybe.both imageJsonToEntry url image

imageJsonToEntry url imageJson =
		let getProp p = Json.getProp p imageJson
			getIntOrZero p = getProp p |> Json.toInt |> Maybe.getDefault 0
		in
			{
				url = url,
				width = getIntOrZero "width",
				height = getIntOrZero "height",
				thumbnailUrl = getProp "thumbnailLink" |> Json.toString |> Maybe.getDefault "",
				thumbnailWidth = getIntOrZero "thumbnailWidth",
				thumbnailHeight = getIntOrZero "thumbnailHeight",
			}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment