JSON¶
The baseline format — no dependencies (uses the standard-library json).
from omnist import read_json, write_json, Doc
d = Doc.from_json('{"name": "Ann", "tags": ["x", "y"]}')
d.to_json() # '{"name": "Ann", "tags": ["x", "y"]}'
How it maps¶
- A JSON object becomes a list of edges.
- A key whose value is an array expands into one edge per item (a repeated
label):
{"tags": ["x", "y"]}→[(tags, "x"), (tags, "y")]. - A nested object becomes a nested node; scalars are leaves.
That's the raw edge list, not a round-tripped projection — read_json itself
returns it directly:
from omnist import read_json
read_json('{"tags": ["x", "y"]}')
# [('tags', 'x'), ('tags', 'y')]
Reading¶
Without a schema¶
JSON has no native date/time type, so a date-looking string comes back as a
plain str — there's nothing else it could be:
from omnist import read_json
read_json('{"d": "2024-01-01", "n": 3}')
# [('d', '2024-01-01'), ('n', 3)]
type(dict(read_json('{"d": "2024-01-01", "n": 3}'))['d'])
# <class 'str'>
With a schema¶
schema= upgrades each leaf to match the schema's declared scalar, wherever
the conversion is value-exact — here the date string becomes a real
datetime.date, and the integer 3 becomes the float 3.0 (a number
field always materializes as float). See
schema-directed deserialization for the full
conversion rules.
from omnist import parse_schema, read_json
s = parse_schema('record R { "d": date, "n": number }\nroot R')
read_json('{"d": "2024-01-01", "n": 3}', schema=s)
# [('d', datetime.date(2024, 1, 1)), ('n', 3.0)]
Doc.from_json(text, schema=s) is the same conversion through the Doc
wrapper — Doc.from_json just calls read_json underneath:
from omnist import Doc
Doc.from_json('{"d": "2024-01-01", "n": 3}', schema=s).to_data()
# [('d', datetime.date(2024, 1, 1)), ('n', 3.0)]
Writing¶
write_json groups same-label edges back into a JSON array. A label seen more
than once becomes a list; a label seen exactly once stays a single value (the
count-1 rule: a single-element array can't be told apart from a single
value, so it always serializes as a bare value). write_json (like every
writer) never takes a schema — a writer serializes the Document exactly as it
is, with no schema-driven override of this rule. Schema awareness is read-side
only.
from omnist import write_json, Doc
write_json([("tag", "x"), ("tag", "y")]) # '{"tag": ["x", "y"]}'
write_json([("tag", "x")]) # '{"tag": "x"}'
Doc.of({"tag": ["x", "y"]}).to_json() # '{"tag": ["x", "y"]}'
JSON has no date type, so a
date/time/datetimeleaf is written out as an ISO-8601 string (reported astemporal.stringified), and reads back as a plainstrunlessschema=is given on the way back in. See adjustment reports.
Notes¶
- JSON has no
NaN/Infinity; writing one is reported asfloat.special, an error-severity adjustment. date,time, anddatetimestrings are mutually exclusive even before a schema is involved:"2024-01-01"could only ever satisfydate, notdatetime(it has no time component to satisfy it with).- A bare top-level array (
[1, 2, 3]) has no labels, so it isn't a Document on its own — wrap it under a key. - See the comparison table for how JSON's quirks stack up against the other formats.