On this page
std/json
Source EditThis module implements a simple high performance JSON parser. JSON (JavaScript Object Notation) is a lightweight data-interchange format that is easy for humans to read and write (unlike XML). It is easy for machines to parse and generate. JSON is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999.
See also
Overview
Parsing JSON
JSON often arrives into your program (via an API or a file) as a string. The first step is to change it from its serialized form into a nested object structure called a JsonNode.
The parseJson procedure takes a string containing JSON and returns a JsonNode object. This is an object variant and it is either a JObject, JArray, JString, JInt, JFloat, JBool or JNull. You check the kind of this object variant by using the kind accessor.
For a JsonNode who's kind is JObject, you can access its fields using the [] operator. The following example shows how to do this:
import std/json
let jsonNode = parseJson("""{"key": 3.14}""")
doAssert jsonNode.kind == JObject
doAssert jsonNode["key"].kind == JFloat
Reading values
Once you have a JsonNode, retrieving the values can then be achieved by using one of the helper procedures, which include:
getIntgetFloatgetStrgetBool
To retrieve the value of "key" you can do the following:
import std/json
let jsonNode = parseJson("""{"key": 3.14}""")
doAssert jsonNode["key"].getFloat() == 3.14
Important: The [] operator will raise an exception when the specified field does not exist.
Handling optional keys
By using the {} operator instead of [], it will return nil when the field is not found. The get-family of procedures will return a type's default value when called on nil.
import std/json
let jsonNode = parseJson("{}")
doAssert jsonNode{"nope"}.getInt() == 0
doAssert jsonNode{"nope"}.getFloat() == 0
doAssert jsonNode{"nope"}.getStr() == ""
doAssert jsonNode{"nope"}.getBool() == false
Using default values
The get-family helpers also accept an additional parameter which allow you to fallback to a default value should the key's values be null:
import std/json
let jsonNode = parseJson("""{"key": 3.14, "key2": null}""")
doAssert jsonNode["key"].getFloat(6.28) == 3.14
doAssert jsonNode["key2"].getFloat(3.14) == 3.14
doAssert jsonNode{"nope"}.getFloat(3.14) == 3.14 # note the {}
Unmarshalling
In addition to reading dynamic data, Nim can also unmarshal JSON directly into a type with the to macro.
Note: Use Option for keys sometimes missing in json responses, and backticks around keys with a reserved keyword as name.
import std/json
import std/options
type
User = object
name: string
age: int
`type`: Option[string]
let userJson = parseJson("""{ "name": "Nim", "age": 12 }""")
let user = to(userJson, User)
if user.`type`.isSome():
assert user.`type`.get() != "robot"
Creating JSON
This module can also be used to comfortably create JSON using the %* operator:
import std/json
var hisName = "John"
let herAge = 31
var j = %*
[
{ "name": hisName, "age": 30 },
{ "name": "Susan", "age": herAge }
]
var j2 = %* {"name": "Isaac", "books": ["Robot Dreams"]}
j2["details"] = %* {"age":35, "pi":3.1415}
echo j2
See also: std/jsonutils for hookable json serialization/deserialization of arbitrary types.
Example:
import std/json
## Note: for JObject, key ordering is preserved, unlike in some languages,
## this is convenient for some use cases. Example:
type Foo = object
a1, a2, a0, a3, a4: int
doAssert $(%* Foo()) == """{"a1":0,"a2":0,"a0":0,"a3":0,"a4":0}"""
Imports
Types
Procs
-
proc `%`(b: bool): JsonNode {....raises: [], tags: [], forbids: [].} -
Generic constructor for JSON data. Creates a new
JBool JsonNode. Source Edit -
proc `%`(keyVals: openArray[tuple[key: string, val: JsonNode]]): JsonNode {. ...raises: [], tags: [], forbids: [].} -
Generic constructor for JSON data. Creates a new
JObject JsonNodeSource Edit -
proc `%`(n: BiggestInt): JsonNode {....raises: [], tags: [], forbids: [].} -
Generic constructor for JSON data. Creates a new
JInt JsonNode. Source Edit -
proc `%`(n: BiggestUInt): JsonNode {....raises: [], tags: [], forbids: [].} -
Generic constructor for JSON data. Creates a new
JInt JsonNode. Source Edit -
proc `%`(n: float): JsonNode {....raises: [], tags: [], forbids: [].} -
Generic constructor for JSON data. Creates a new
JFloat JsonNode.Example:
Source Editassert $(%[NaN, Inf, -Inf, 0.0, -0.0, 1.0, 1e-2]) == """["nan","inf","-inf",0.0,-0.0,1.0,0.01]""" assert (%NaN).kind == JString assert (%0.0).kind == JFloat -
proc `%`(n: int): JsonNode {....raises: [], tags: [], forbids: [].} -
Generic constructor for JSON data. Creates a new
JInt JsonNode. Source Edit -
proc `%`(n: uint): JsonNode {....raises: [], tags: [], forbids: [].} -
Generic constructor for JSON data. Creates a new
JInt JsonNode. Source Edit -
proc `%`(o: enum): JsonNode -
Construct a JsonNode that represents the specified enum value as a string. Creates a new
JString JsonNode. Source Edit -
proc `%`(o: ref object): JsonNode -
Generic constructor for JSON data. Creates a new
JObject JsonNodeSource Edit -
proc `%`(s: string): JsonNode {....raises: [], tags: [], forbids: [].} -
Generic constructor for JSON data. Creates a new
JString JsonNode. Source Edit -
proc `%`[T](elements: openArray[T]): JsonNode -
Generic constructor for JSON data. Creates a new
JArray JsonNodeSource Edit -
proc `[]`(node: JsonNode; index: BackwardsIndex): JsonNode {.inline, ...raises: [], tags: [], forbids: [].} -
Gets the node at
array.len-iin an array through the^operator.i.e.
j[^i]is a shortcut forj[j.len-i].Example:
Source Editlet j = parseJson("[1,2,3,4,5]") doAssert j[^1].getInt == 5 doAssert j[^2].getInt == 4 -
proc `[]`(node: JsonNode; index: int): JsonNode {.inline, ...raises: [], tags: [], forbids: [].} -
Gets the node at
indexin an Array. Result is undefined ifindexis out of bounds, but as long as array bound checks are enabled it will result in an exception. Source Edit -
proc parseJson(buffer: string; rawIntegers = false; rawFloats = false): JsonNode {. ...raises: [IOError, OSError, JsonParsingError, ValueError], tags: [ReadIOEffect, WriteIOEffect], forbids: [].} -
Parses JSON from
buffer. Ifbuffercontains extra data, it will raiseJsonParsingError. IfrawIntegersis true, integer literals will not be converted to aJIntfield but kept as raw numbers viaJString. IfrawFloatsis true, floating point literals will not be converted to aJFloatfield but kept as raw numbers viaJString. Source Edit -
proc parseJson(s: Stream; filename: string = ""; rawIntegers = false; rawFloats = false): JsonNode {. ...raises: [IOError, OSError, IOError, OSError, JsonParsingError, ValueError], tags: [ReadIOEffect, WriteIOEffect], forbids: [].} -
Parses from a stream
sinto aJsonNode.filenameis only needed for nice error messages. Ifscontains extra data, it will raiseJsonParsingError. This closes the streamsafter it's done. IfrawIntegersis true, integer literals will not be converted to aJIntfield but kept as raw numbers viaJString. IfrawFloatsis true, floating point literals will not be converted to aJFloatfield but kept as raw numbers viaJString. Source Edit -
proc pretty(node: JsonNode; indent = 2): string {....raises: [], tags: [], forbids: [].} -
Returns a JSON Representation of
node, with indentation and on multiple lines.Similar to prettyprint in Python.
Example:
Source Editlet j = %* {"name": "Isaac", "books": ["Robot Dreams"], "details": {"age": 35, "pi": 3.1415}} doAssert pretty(j) == """ { "name": "Isaac", "books": [ "Robot Dreams" ], "details": { "age": 35, "pi": 3.1415 } }""" -
proc to[T](node: JsonNode; t: typedesc[T]): T -
Unmarshals the specified node into the object type specified.
Known limitations:
- Heterogeneous arrays are not supported.
- Sets in object variants are not supported.
- Not nil annotations are not supported.
Example:
Source Editlet jsonNode = parseJson(""" { "person": { "name": "Nimmer", "age": 21 }, "list": [1, 2, 3, 4] } """) type Person = object name: string age: int Data = object person: Person list: seq[int] var data = to(jsonNode, Data) doAssert data.person.name == "Nimmer" doAssert data.person.age == 21 doAssert data.list == @[1, 2, 3, 4] -
proc toUgly(result: var string; node: JsonNode) {....raises: [], tags: [], forbids: [].} -
Converts
nodeto its JSON Representation, without regard for human readability. Meant to improve$string conversion performance.JSON representation is stored in the passed
resultThis provides higher efficiency than the
Source Editprettyprocedure as it does not attempt to format the resulting JSON to make it human readable. -
proc `{}`(node: JsonNode; index: varargs[int]): JsonNode {....raises: [], tags: [], forbids: [].} -
Traverses the node and gets the given value. If any of the indexes do not exist, returns
nil. Also returnsnilif one of the intermediate data structures is not an array. Source Edit -
proc `{}`(node: JsonNode; key: string): JsonNode {....raises: [], tags: [], forbids: [].} -
Gets a field from a
node. Ifnodeis nil or not an object or value atkeydoes not exist, returns nil Source Edit -
proc `{}`(node: JsonNode; keys: varargs[string]): JsonNode {....raises: [], tags: [], forbids: [].} -
Traverses the node and gets the given value. If any of the keys do not exist, returns
nil. Also returnsnilif one of the intermediate data structures is not an object.This proc can be used to create tree structures on the fly (sometimes called autovivification):
Example:
Source Editvar myjson = %* {"parent": {"child": {"grandchild": 1}}} doAssert myjson{"parent", "child", "grandchild"} == newJInt(1)
Iterators
-
iterator parseJsonFragments(s: Stream; filename: string = ""; rawIntegers = false; rawFloats = false): JsonNode {. ...raises: [IOError, OSError, IOError, OSError, JsonParsingError, ValueError], tags: [ReadIOEffect, WriteIOEffect], forbids: [].} -
Parses from a stream
sintoJsonNodes.filenameis only needed for nice error messages. The JSON fragments are separated by whitespace. This can be substantially faster than the comparable loopfor x in splitWhitespace(s): yield parseJson(x). This closes the streamsafter it's done. IfrawIntegersis true, integer literals will not be converted to aJIntfield but kept as raw numbers viaJString. IfrawFloatsis true, floating point literals will not be converted to aJFloatfield but kept as raw numbers viaJString. Source Edit
Macros
Templates
Exports
- $, $, $, $, $, $, JsonEventKind, JsonError, JsonParser, JsonKindError, open, open, open, open, open, open, close, close, close, close, close, str, getInt, getFloat, kind, kind, getColumn, getLine, getFilename, errorMsg, errorMsgExpected, next, JsonParsingError, raiseParseErr, nimIdentNormalize
© 2006–2024 Andreas Rumpf
Licensed under the MIT License.
https://nim-lang.org/docs/json.html