Rhombus JSON
JSON
from_  string
from_  bytes
read
to_  string
to_  bytes
write
8.16.0.4

Rhombus JSON🔗ℹ

 import: json package: rhombus-json-lib

The json library provides functions to read and write using the JSON exchange format. See See the JSON web site and the JSON RFC for more information about JSON.

annotation

json.JSON

The json.JSON annotation matches a subset of Rhombus built-in datatypes that can be read and written in JSON format:

> { "a": 1, "b": [2, 3.0, #true] } is_a json.JSON

#true

> { #'a: 1 } is_a json.JSON

#false

To check whether a list or map satisfies json.JSON, the list or map’s content must be traversed recursively. However, a #true result is cached through a weak reference, so checking again for the same (in the sense of ===) list or map produces #true immediately. The result for any value within the list or map is similarly cached.

function

fun json.from_string(

  str :: String,

  ~replace_malformed_surrogate: replacement :: Any.to_boolean = #false

) :: json.JSON

 

function

fun json.from_bytes(

  bstr :: Bytes,

  ~replace_malformed_surrogate: replacement :: Any.to_boolean = #false

) :: json.JSON

 

function

fun json.read(

  ~in: inp :: Port.Input = Port.Input.current(),

  ~replace_malformed_surrogate: replacement :: Any.to_boolean = #false

) :: json.JSON || Port.Input.EOF

Parses a JSON representation to a json.JSON value.

For json.from_string and json.from_bytes, the string or byte string must contain a single JSON encoding.

> json.from_string("1")

1

> json.from_string("{\"a\": [1, 2]}")

{"a": [1, 2]}

> json.from_string("1 2")

json.from_string: found additional value in string

  additional value: 2

> json.from_string("")

json.from_string: no value in string

> json.from_bytes(#"{\"a\": [1, 3.0, null, false]}")

{"a": [1, 3.0, #'null, #false]}

The json.read function reads the next JSON encoding from inp, stopping (and leaving remaining bytes in the port intact) as soon as it finds a complete JSON value; true, false, or null must be followed by an end-of-file or a non-alphanumeric character (such as whitespace). If no JSON representation is present in inp before an end-of-file, the result is Port.Input.eof.

> def inp = Port.Input.open_string("1 true[\"a\", {\"b\": 3.0}]")

> json.read(~in: inp)

1

> json.read(~in: inp)

#true

> json.read(~in: inp)

["a", {"b": 3.0}]

> json.read(~in: inp)

Port.eof

If replacement is true, then an unpaired surrogate escape in an input JSON string representation is replaced with Char"\uFFFD". Otherwise, an unpaired surrogate is treated as an input error.

> json.from_string(@str{"\u03BB"})

"λ"

> json.from_string(@str{"\uD870"})

json.from_string: bad string \u escape, missing second half of a UTF-16 pair

> json.from_string(@str{"\uD870"},

                   ~replace_malformed_surrogate: #true)

"�"

function

fun json.to_string(j :: json.JSON) :: String

 

function

fun json.to_bytes(j :: json.JSON) :: Bytes

 

function

fun json.write(

  j :: json.JSON,

  ~out: outp :: Port.Output = Port.Output.current()

) :: Void

Produces a JSON representation of a json.JSON value.

The json.to_string and json.to_bytes functions return the JSON representation as a string or byte string, while json.write prints that representation to an output port.

> json.to_string(1)

"1"

> json.to_string({ "a": 1, "b": [2, 3.0, #'null, #false] })

"{\"a\":1,\"b\":[2,3.0,null,false]}"

> json.to_bytes(1)

Bytes.copy(#"1")

> json.write([2, 3, 4])

[2,3,4]

> block:

    let outp = Port.Output.open_string()

    json.write([2, 3, 4], ~out: outp)

    json.write({ "a": 0 }, ~out: outp)

    outp.get_string()

"[2,3,4]{\"a\":0}"