March Docs

Json

Json module: JSON encoding and decoding.

Types: JsonValue = Null | Bool(Bool) | Number(Float) | Str(String) | Array(List(JsonValue)) | Object(List((String, JsonValue)))

Note: Object uses an association list (ordered, allows duplicate keys). Key lookup uses the first occurrence.

Functions: parse(String) -> Result(JsonValue, String) to_string(JsonValue) -> String get(JsonValue, String) -> Option(JsonValue) get_in(JsonValue, List(String)) -> Option(JsonValue) encode_null() -> JsonValue encode_bool(Bool) -> JsonValue encode_number(Float) -> JsonValue encode_int(Int) -> JsonValue encode_string(String) -> JsonValue encode_array(List(JsonValue)) -> JsonValue encode_object(List((String, JsonValue))) -> JsonValue

Types

typeJsonValueJsonValue =#
typeJsonPathStepJsonPathStep = JPathField(String) | JPathIndex(Int)#

One step of a JSONPath. Steps are stored OUTERMOST-FIRST, so a decoder descending into a field prepends -- see decode_error_under.

typeDecodeErrorDecodeError = DecodeError(String, List(JsonPathStep), Int)#

A typed decoding failure: what was wrong, where in the document structure, and (when known) the absolute byte offset of the record it came from. The offset is 0 - 1 when unknown -- decoding a value already in memory has no byte position.

Path shape follows aeson and Jackson: a flat list of steps rendered JSONPath-style. Elm's recursive error tree exists to support oneOf, which reports several failed branches at one position; with no combinator layer a flat list carries the same information for less. Revisit if oneOf is ever added.

typeJsonPathJsonPath = Key(String) | Index(Int)#

A single step in a JSON path: either an object key or an array index.

Functions

fndecode_error_atdecode_error_at(off, e)#

Attach an absolute byte offset to a DecodeError, replacing any offset it already carried. A negative offset means "unknown".

Examples

march> Json.decode_error_to_string(Json.decode_error_at(4096, DecodeError("expected Int", [JPathField("id")], -1)))
"$.id (byte 4096): expected Int"
fndecode_error_to_stringdecode_error_to_string(e)#

Render a DecodeError as $.users[3].id: expected Int, with the byte offset when known (non-negative): $.id (byte 4096): expected Int. An empty path renders as $.

Examples

march> Json.decode_error_to_string(DecodeError("expected Int", [JPathField("users"), JPathIndex(3), JPathField("id")], -1))
"$.users[3].id: expected Int"
march> Json.decode_error_to_string(DecodeError("expected Object", [], 0))
"$ (byte 0): expected Object"
fndecode_error_underdecode_error_under(step, e)#

Push step onto the front of a DecodeError's path, as a decoder does when it descends: an error raised inside field id and then wrapped by the caller decoding element 0 renders as $[0].id.

Examples

march> Json.decode_error_to_string(Json.decode_error_under(JPathIndex(0), DecodeError("expected Int", [JPathField("id")], -1)))
"$[0].id: expected Int"
fnencode_arrayencode_array(xs) do Array(xs) end#

Construct a JSON array value from a list of values.

Examples

march> Json.to_string(Json.encode_array([Json.encode_bool(true), Json.encode_null()]))
"[true,null]"
march> Json.to_string(Json.encode_array([]))
"[]"
fnencode_boolencode_bool(b) do Bool(b) end#

Construct a JSON boolean value (the Bool constructor).

Examples

march> Json.to_string(Json.encode_bool(false))
"false"
fnencode_intencode_int(n) do Number(int_to_float(n)) end#

Construct a JSON number value from an Int. JSON has a single number type, so the Int is converted to a Float (Number(int_to_float(n))); integers beyond 2^53 lose precision.

Examples

march> Json.encode_int(3) == Json.encode_number(3.0)
true
march> Json.to_string(Json.encode_int(-7))
"-7"
fnencode_nullencode_null() do Null end#

Construct a JSON null value (the Null constructor).

Examples

march> Json.to_string(Json.encode_null())
"null"
fnencode_numberencode_number(f) do Number(f) end#

Construct a JSON number value from a Float. to_string prints a Float with no fractional part without a decimal point.

Examples

march> Json.to_string(Json.encode_number(2.5))
"2.5"
march> Json.to_string(Json.encode_number(2.0))
"2"
fnencode_objectencode_object(kvs) do Object(kvs) end#

Construct a JSON object value from a list of (key, value) pairs. The order is kept and duplicate keys are not removed; get returns the first occurrence.

Examples

march> Json.to_string(Json.encode_object([("a", Json.encode_int(1)), ("b", Json.encode_null())]))
"{\"a\":1,\"b\":null}"
march> Json.get(Json.encode_object([("k", Json.encode_int(1)), ("k", Json.encode_int(2))]), "k") == Some(Json.encode_int(1))
true
fnencode_stringencode_string(s) do Str(s) end#

Construct a JSON string value. Escaping happens later, in to_string.

Examples

march> Json.to_string(Json.encode_string("a\"b"))
"\"a\\\"b\""
fngetget(jv : JsonValue, key : String) : Option(JsonValue)#

Retrieve a field from a JSON Object by key. Returns Some(value) if found, or None otherwise. If jv is not an Object, returns None.

march> Json.get(Object([("x", Number(1.0))]), "x") == Some(Number(1.0))
true
march> Json.get(Null, "x")
None
fnget_atget_at(jv : JsonValue, i : Int) : Option(JsonValue)#

Retrieve a JSON Array element by 0-based index. Returns Some(value) if in range, or None otherwise (also None if jv is not an Array, or if i is negative).

march> Json.get_at(Array([Number(1.0), Number(2.0)]), 1) == Some(Number(2.0))
true
march> Json.get_at(Array([Number(1.0)]), 5)
None
fnget_fieldget_field(kvs : List((String, JsonValue)), key : String) : Option(JsonValue)#

Look up a key in a JSON object's raw key-value list directly -- the list already bound by matching Object(kvs), rather than a JsonValue. Returns Some(value) if found, or None otherwise. Used by the generated from_json record decoder, which destructures Object(kvs) once and then looks up each field by name without re-matching the wrapper each time.

march> Json.get_field([("x", Number(1.0))], "x") == Some(Number(1.0))
true
march> Json.get_field([], "x")
None
fnget_inget_in(jv : JsonValue, keys : List(String)) : Option(JsonValue)#

Nested field access: traverse a path of keys into nested JSON Objects. Returns Some(value) if the full path exists, or None if any step fails.

march> let obj = Object([("a", Object([("b", Object([("c", Bool(true))]))]))])
march> Json.get_in(obj, ["a", "b", "c"])  -- equivalent to obj.a.b.c
Some(Bool(true))
march> let obj = Object([("a", Object([("b", Object([("c", Bool(true))]))]))])
march> Json.get_in(obj, ["a", "x"])
None

Object-only. For paths that include array indices, use get_path.

fnget_pathget_path(jv : JsonValue, path : List(JsonPath)) : Option(JsonValue)#

Mixed-segment path access for JSON values nested in objects and arrays. Each step is Key("name") for an object lookup or Index(i) for an array index. Returns Some(value) if the full path exists, or None if any step fails.

Write JsonPath.Key when Key alone is ambiguous with another type's constructor in scope.

Examples

march> let jv = Json.encode_object([("items", Json.encode_array([Json.encode_object([("name", Json.encode_string("pen"))])]))])
march> Json.get_path(jv, [JsonPath.Key("items"), Index(0), JsonPath.Key("name")]) == Some(Json.encode_string("pen"))
true
march> let jv = Json.encode_object([("items", Json.encode_array([Json.encode_object([("name", Json.encode_string("pen"))])]))])
march> Json.get_path(jv, [JsonPath.Key("items"), Index(3)])
None
march> let jv = Json.encode_object([("items", Json.encode_array([Json.encode_object([("name", Json.encode_string("pen"))])]))])
march> Json.get_path(jv, []) == Some(jv)
true
fnparseparse(s)#

Parse a JSON string into a JsonValue. Returns Ok(value) on success, Err(message) on parse error.

march> Json.parse("null")
Ok(Null)
march> Json.parse("42") == Ok(Number(42.0))
true
march> Json.parse("[1, 2, 3]") == Ok(Array([Number(1.0), Number(2.0), Number(3.0)]))
true
march> Json.parse("{\"x\": 1}") == Ok(Object([("x", Number(1.0))]))
true
fnto_stringto_string(jv)#

Convert a JsonValue to its JSON string representation.

march> Json.to_string(Null)
"null"
march> Json.to_string(Bool(true))
"true"
march> Json.to_string(Number(3.14))
"3.14"
march> Json.to_string(Str("hi"))
"\"hi\""