LEVIATHAN v962456e · 962456eee1

Standard Library

class JsonValue

A JSON value: null, a boolean, a number, a string, an array or an object.

since 0.1.0-alpha.1linuxwindowswasm

Overview

A JsonValue holds exactly one of those kinds. Build values with the labeled constructors (JsonValue::ofStr("x"), JsonValue::ofArray(items), and so on), or get them from json::parse. Test the kind with isNull, isBool, isNum, isStr, isArray and isObject. Read the contents with the as... methods, which give None when the kind does not match, or navigate with at and atOrNone. render and renderPretty turn a value back into JSON text.

Numbers are always stored as floats, so the JSON number 30 is read back as 30.0 and renders as 30.000000. Use asNum() and convert with toInt() when you need an integer.

Description

JsonValue is a single class that represents every kind of JSON value. The language has no type aliases, so a recursive union such as "null, bool, number, string, array of this, object of this" cannot be declared; instead each JsonValue carries an integer kind tag and the matching payload.

kind JSON value test
0 null isNull()
1 true / false isBool()
2 number (an IEEE double) isNum()
3 string isStr()
4 array isArray()
5 object isObject()

A tree is produced by json::parse, or built by hand with one of the six labeled constructors JsonValue::ofNull(), ofBool(bool), ofNum(float), ofStr(string), ofArray(Array<JsonValue>) and ofObject(Map<string, JsonValue>).

There are two ways to read a tree, and they fail differently:

  • Typed accessors asBool(), asNum(), asStr(), asArray() and asObject() return None when the value is of a different kind. They never throw.
  • Navigation with at(int) and at(string) is loud. It throws a RuntimeException when the value is not an array (or object), when the index is out of range, or when the key is missing. atOrNone(key) is the quiet object lookup: it returns None for a missing key and for a value that is not an object.

size() is the element count of an array, the entry count of an object, and 0 for every other kind. render() writes compact JSON, and renderPretty(indent) writes the same value with a line per element, indented by indent spaces per level; an empty array or object stays on one line as [] or {}.

Kinds, accessors and navigation

JsonValue n = JsonValue::ofNum(2.5);
JsonValue s = JsonValue::ofStr("hi");
JsonValue a = JsonValue::ofArray([n, s, JsonValue::ofBool(false), JsonValue::ofNull()]);
Map<string, JsonValue> m = Map();
m["k"] = a;
JsonValue o = JsonValue::ofObject(m);
console.writeln("${n.kind} ${s.kind} ${a.kind} ${o.kind}");
console.writeln("${a.size()} ${o.size()} ${s.size()}");
console.writeln((n.asNum() ?? 0.0).toString());
console.writeln((n.asStr() == None).toString());
console.writeln(o.at("k").at(0).render());
console.writeln((o.atOrNone("zz") == None).toString());
try {
    s.at(0);
} catch (RuntimeException e) {
    console.writeln(e.message);
}
2 3 4 5
4 1 0
2.500000
true
2.500000
true
JsonValue.at(int): not an array

Rules

  • at(int) throws JsonValue.at(int): not an array on a value that is not an array, and the ordinary bounds error on an index outside the array.
  • at(string) throws JsonValue.at(string): not an object on a value that is not an object, and a key not found error for a missing key.
  • Number payloads are float, so a number renders with six decimals: JsonValue::ofNum(3.0).render() is 3.000000.
  • An object keeps its keys in insertion order, and render() and renderPretty() write them in that order.
  • The kind, b, num, str, items and fields members are public, but code should prefer the typed accessors, which keep a kind mismatch from reading a stale payload.

Examples

Pretty-printing

JsonValue a = JsonValue::ofArray([JsonValue::ofNum(2.5), JsonValue::ofStr("hi"), JsonValue::ofNull()]);
console.writeln(a.renderPretty(4));
console.writeln(JsonValue::ofArray([]).renderPretty(2));
[
    2.500000,
    "hi",
    null
]
[]

Examples

Parsing a document and reading it

string text = "{\"name\":\"Ann\",\"age\":30,\"tags\":[\"a\",\"b\"]}";
JsonValue doc = json::parse(text) ?? JsonValue::ofNull();
console.writeln(doc.at("name").asStr() ?? "?");
console.writeln((doc.at("age").asNum() ?? 0.0).toInt());
console.writeln(doc.at("tags").at(1).asStr() ?? "?");
console.writeln(doc.at("tags").size());
console.writeln(doc.at("name").asNum() == None);
console.writeln(doc.render());
Ann
30
b
2
true
{"name":"Ann","age":30.000000,"tags":["a","b"]}

Constructors

ofArray

JsonValue::ofArray(Array<JsonValue> v)

Create a JSON array.

Parameters

v
The elements, in order.

Examples

Array<JsonValue> items = [JsonValue::ofNum(1.0), JsonValue::ofStr("two"), JsonValue::ofNull()];
JsonValue v = JsonValue::ofArray(items);
console.writeln(v.size());
console.writeln(v.render());
3
[1.000000,"two",null]

ofBool

JsonValue::ofBool(bool v)

Create a JSON boolean.

Parameters

v
The boolean value.

Examples

JsonValue v = JsonValue::ofBool(true);
console.writeln(v.isBool());
console.writeln(v.render());
true
true

ofNull

JsonValue::ofNull()

Create the JSON value null.

Examples

JsonValue v = JsonValue::ofNull();
console.writeln(v.isNull());
console.writeln(v.render());
true
null

ofNum

JsonValue::ofNum(float v)

Create a JSON number.

Parameters

v
The numeric value.

Examples

JsonValue v = JsonValue::ofNum(1.5);
console.writeln(v.isNum());
console.writeln(v.render());
true
1.500000

ofObject

JsonValue::ofObject(Map<string, JsonValue> v)

Create a JSON object.

Parameters

v
The members, keyed by name.

Examples

Map<string, JsonValue> members;
members = members.with("ok", JsonValue::ofBool(true));
JsonValue v = JsonValue::ofObject(members);
console.writeln(v.size());
console.writeln(v.render());
1
{"ok":true}

ofStr

JsonValue::ofStr(string v)

Create a JSON string.

Parameters

v
The text of the string.

Examples

JsonValue v = JsonValue::ofStr("say \"hi\"");
console.writeln(v.isStr());
console.writeln(v.render());
true
"say \"hi\""

Fields

b

bool b

The boolean value, meaningful only when kind is 1.

fields

Map<string, JsonValue> fields

The members of the object, meaningful only when kind is 5.

items

The elements, meaningful only when kind is 4.

kind

int kind

The kind tag: 0 for null, 1 for a boolean, 2 for a number, 3 for a string, 4 for an array and 5 for an object. The is... methods are the usual way to test it.

num

float num

The numeric value, meaningful only when kind is 2.

str

string str

The string value, meaningful only when kind is 3.

Methods

asArray

asArray() -> Array<JsonValue> | None

Read the value as an array of values.

Returns

The elements, or None when the value is not an array.

Examples

JsonValue v = json::parse("[1, 2, 3]") ?? JsonValue::ofNull();
Array<JsonValue>? items = v.asArray();
console.writeln(items != None ? items.length() : 0);
console.writeln(JsonValue::ofNull().asArray() == None);
3
true

See also: isArray

asBool

asBool() -> bool | None

Read the value as a boolean.

Returns

The boolean, or None when the value is not a boolean.

Examples

console.writeln(JsonValue::ofBool(true).asBool() ?? false);
console.writeln(JsonValue::ofStr("true").asBool() == None);
true
true

See also: isBool

asNum

asNum() -> float | None

Read the value as a number.

Returns

The number, or None when the value is not a number.

Examples

console.writeln(JsonValue::ofNum(2.5).asNum() ?? 0.0);
console.writeln(JsonValue::ofStr("2.5").asNum() == None);
2.500000
true

See also: isNum

asObject

asObject() -> Map<string, JsonValue> | None

Read the value as a map of member names to values.

Returns

The members, or None when the value is not an object.

Examples

JsonValue v = json::parse("{\"a\": 1, \"b\": 2}") ?? JsonValue::ofNull();
Map<string, JsonValue>? members = v.asObject();
console.writeln(members != None ? members.length() : 0);
console.writeln(JsonValue::ofNull().asObject() == None);
2
true

See also: isObject

asStr

asStr() -> string | None

Read the value as a string.

Returns

The string, or None when the value is not a string.

Examples

console.writeln(JsonValue::ofStr("hi").asStr() ?? "none");
console.writeln(JsonValue::ofNum(1.0).asStr() ?? "none");
hi
none

See also: isStr

at

at(int i) -> JsonValue

Get an element of an array by position.

Navigation with at is strict: it throws instead of returning None, so a wrong path fails loudly. Use atOrNone or the is... tests when the shape of the data is not known in advance.

Parameters

i
The zero-based index.

Returns

The element at that index.

Throws

RuntimeException
when this value is not an array, or when i is out of range.

Examples

JsonValue v = json::parse("[10, 20, 30]") ?? JsonValue::ofNull();
console.writeln((v.at(1).asNum() ?? 0.0).toInt());
try {
    v.at(5);
} catch (RuntimeException e) {
    console.writeln(e.message);
}
try {
    JsonValue::ofStr("x").at(0);
} catch (RuntimeException e) {
    console.writeln(e.message);
}
20
index 5 out of bounds (length 3)
JsonValue.at(int): not an array
at(string key) -> JsonValue

Get an object member by name.

Like at(int), this throws when the navigation does not fit the data. Use atOrNone for a lookup that may miss.

Parameters

key
The member name.

Returns

The value stored under key.

Throws

RuntimeException
when this value is not an object, or when the object has no member key.

See also: atOrNone

atOrNone

atOrNone(string key) -> JsonValue | None

Look up an object member by name, giving None when it is absent.

Unlike at, this never throws: a missing member, and a value that is not an object at all, both give None.

Parameters

key
The member name.

Returns

The member's value, or None when this is not an object or has no such member.

Examples

JsonValue v = json::parse("{\"a\": true}") ?? JsonValue::ofNull();
console.writeln(v.atOrNone("a") != None);
console.writeln(v.atOrNone("b") == None);
console.writeln(JsonValue::ofNull().atOrNone("a") == None);
true
true
true

See also: at

isArray

isArray() -> bool

Test whether this value is an array.

Returns

true when the kind is array.

Examples

JsonValue v = json::parse("[1, 2]") ?? JsonValue::ofNull();
console.writeln(v.isArray());
console.writeln(v.isObject());
true
false

See also: asArray

isBool

isBool() -> bool

Test whether this value is a boolean.

Returns

true when the kind is boolean.

Examples

console.writeln(JsonValue::ofBool(false).isBool());
console.writeln(JsonValue::ofNum(0.0).isBool());
true
false

See also: asBool

isNull

isNull() -> bool

Test whether this value is null.

Returns

true when the kind is null.

Examples

JsonValue v = json::parse("null") ?? JsonValue::ofBool(false);
console.writeln(v.isNull());
console.writeln(JsonValue::ofStr("").isNull());
true
false

See also: isBool

isNum

isNum() -> bool

Test whether this value is a number.

Returns

true when the kind is number.

Examples

console.writeln(JsonValue::ofNum(2.5).isNum());
console.writeln(JsonValue::ofStr("2.5").isNum());
true
false

See also: asNum

isObject

isObject() -> bool

Test whether this value is an object.

Returns

true when the kind is object.

Examples

JsonValue v = json::parse("{\"a\": 1}") ?? JsonValue::ofNull();
console.writeln(v.isObject());
console.writeln(v.isArray());
true
false

See also: asObject

isStr

isStr() -> bool

Test whether this value is a string.

Returns

true when the kind is string.

Examples

console.writeln(JsonValue::ofStr("x").isStr());
console.writeln(JsonValue::ofNull().isStr());
true
false

See also: asStr

render

render() -> string

Render the value as compact JSON text.

There is no whitespace between tokens. Strings are escaped (", \, and control characters; non-ASCII text passes through unchanged). Numbers use the float text form, so 30 renders as 30.000000. Object members appear in the map's iteration order.

Returns

The JSON text.

Examples

JsonValue v = json::parse("[1, \"two\", {\"three\": null}]") ?? JsonValue::ofNull();
console.writeln(v.render());
console.writeln(JsonValue::ofStr("line1\nline2").render());
[1.000000,"two",{"three":null}]
"line1\nline2"

See also: renderPretty, parse

renderPretty

renderPretty(int indent) -> string

Render the value as indented, multi-line JSON text.

Each array element and object member goes on its own line, indented by indent spaces per nesting level. Empty arrays and objects render as [] and {}, and scalar values render as render would.

Parameters

indent
The number of spaces per nesting level.

Returns

The JSON text.

Examples

JsonValue v = json::parse("{\"tags\":[\"a\",\"b\"],\"empty\":[]}") ?? JsonValue::ofNull();
console.writeln(v.renderPretty(2));
{
  "tags": [
    "a",
    "b"
  ],
  "empty": []
}

See also: render

size

size() -> int

Get the number of elements or members.

Returns

The element count of an array, the member count of an object, and 0 for every other kind (including a string).

Examples

console.writeln((json::parse("[1, 2, 3]") ?? JsonValue::ofNull()).size());
console.writeln((json::parse("{\"a\": 1}") ?? JsonValue::ofNull()).size());
console.writeln(JsonValue::ofStr("hello").size());
3
1
0

See also

  • json — Parse JSON text into JsonValues and render values back to text.
  • parse — Parse JSON text.