json
Этот модуль реализует простой высокопроизводительный парсер JSON. JSON (JavaScript Object Notation) — это лёгкий формат обмена данными, удобный для чтения и записи человеком (в отличие от XML). Он также легко парсируется и генерируется машинами. JSON основан на подмножестве языка программирования JavaScript, Стандарт ECMA-262 3-го издания — декабрь 1999 года.
Обзор
Парсинг JSON
JSON часто поступает в вашу программу (через API или файл) в виде string. Первый шаг — преобразовать его из сериализованной формы в вложенную структуру объектов, называемую JsonNode.
Процедура parseJson принимает строку, содержащую JSON, и возвращает объект JsonNode. Это вариант объекта, который может быть JObject, JArray, JString, JInt, JFloat, JBool или JNull. Вы проверяете тип этого варианта объекта, используя аксессор kind.
Для JsonNode, тип которого JObject, вы можете получить доступ к его полям, используя оператор [] . Следующий пример демонстрирует это:
import json
let jsonNode = parseJson("""{"key": 3.14}""")
doAssert jsonNode.kind == JObject
doAssert jsonNode["key"].kind == JFloat Чтение значений
После получения JsonNode, извлечение значений можно осуществить, используя одну из вспомогательных процедур, которые включают:
getIntgetFloatgetStrgetBool
Для получения значения "key" можно выполнить следующие действия:
import json
let jsonNode = parseJson("""{"key": 3.14}""")
doAssert jsonNode["key"].getFloat() == 3.14
Важно: оператор [] вызовет исключение, если указанное поле не существует.
Обработка необязательных ключей
Используя оператор {} вместо [], он вернёт nil при отсутствии поля. Процедуры из семейства get вернут значение по умолчанию типа, если они вызваны для nil.
import json
let jsonNode = parseJson("{}")
doAssert jsonNode{"nope"}.getInt() == 0
doAssert jsonNode{"nope"}.getFloat() == 0
doAssert jsonNode{"nope"}.getStr() == ""
doAssert jsonNode{"nope"}.getBool() == false Использование значений по умолчанию
Вспомогательные процедуры из семейства get также принимают дополнительный параметр, позволяющий использовать значение по умолчанию, если значение ключа null:
import 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 {} Распаковка
Помимо чтения динамических данных, Nim также может распаковать JSON непосредственно в тип с помощью макроса to.
Примечание: Используйте Option для ключей, которые иногда отсутствуют в ответах JSON, и обрамляйте ключи с ключевыми словами зарезервированными словами в обратные кавычки.
import json
import 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" Создание JSON
Этот модуль также можно использовать для удобного создания JSON с помощью оператора %*:
import 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
См. также: std/jsonutils для привяземых сериализации/десериализации произвольных типов 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}""" Импорты
- hashes, tables, strutils, lexbase, streams, macros, parsejson, options, since
Типы
JsonNodeKind = enum JNull, JBool, JInt, JFloat, JString, JObject, JArray
- возможные типы узлов JSON Исходный код Редактировать
JsonNode = ref JsonNodeObj
- узел JSON Исходный код Редактировать
JsonNodeObj {...}{.acyclic.} = object isUnquoted: bool case kind*: JsonNodeKind of JString: str*: string of JInt: num*: BiggestInt of JFloat: fnum*: float of JBool: bval*: bool of JNull: nil of JObject: fields*: OrderedTable[string, JsonNode] of JArray: elems*: seq[JsonNode]- Исходный код Редактировать
Процедуры
proc newJString(s: string): JsonNode {...}{.raises: [], tags: [].}- Создаёт новый
JString JsonNode. Исходный код Редактировать proc newJInt(n: BiggestInt): JsonNode {...}{.raises: [], tags: [].}- Создаёт новый
JInt JsonNode. Исходный код Редактировать proc newJFloat(n: float): JsonNode {...}{.raises: [], tags: [].}- Создаёт новый
JFloat JsonNode. Исходный код Редактировать proc newJBool(b: bool): JsonNode {...}{.raises: [], tags: [].}- Создаёт новый
JBool JsonNode. Исходный код Редактировать proc newJNull(): JsonNode {...}{.raises: [], tags: [].}- Создаёт новый
JNull JsonNode. Исходный код Редактировать proc newJObject(): JsonNode {...}{.raises: [], tags: [].}- Создаёт новый
JObject JsonNodeИсходный код Редактировать proc newJArray(): JsonNode {...}{.raises: [], tags: [].}- Создаёт новый
JArray JsonNodeИсходный код Редактировать proc getStr(n: JsonNode; default: string = ""): string {...}{.raises: [], tags: [].}-
Возвращает строковое значение
JString JsonNode.Возвращает
Исходный код Редактироватьdefaultеслиnне являетсяJString, или еслиnравно null. proc getInt(n: JsonNode; default: int = 0): int {...}{.raises: [], tags: [].}-
Возвращает целочисленное значение
JInt JsonNode.Возвращает
Исходный код Редактироватьdefaultеслиnне являетсяJInt, или еслиnравно null. proc getBiggestInt(n: JsonNode; default: BiggestInt = 0): BiggestInt {...}{. raises: [], tags: [].}-
Возвращает значение BiggestInt
JInt JsonNode.Возвращает
Исходный код Редактироватьdefaultеслиnне являетсяJInt, или еслиnравно null. proc getFloat(n: JsonNode; default: float = 0.0): float {...}{.raises: [], tags: [].}-
Возвращает значение с плавающей точкой
JFloat JsonNode.Возвращает
Исходный код Редактироватьdefaultеслиnне являетсяJFloatилиJInt, или еслиnравно null. proc getBool(n: JsonNode; default: bool = false): bool {...}{.raises: [], tags: [].}-
Возвращает логическое значение
JBool JsonNode.Возвращает
Исходный код Редактироватьdefaultеслиnне являетсяJBool, или еслиnравно null. proc getFields(n: JsonNode; default = initOrderedTable(2)): OrderedTable[string, JsonNode] {...}{.raises: [], tags: [].}-
Возвращает пары ключ-значение
JObject JsonNode.Возвращает
Исходный код Редактироватьdefaultеслиnне являетсяJObject, или еслиnравно null. proc getElems(n: JsonNode; default: seq[JsonNode] = @[]): seq[JsonNode] {...}{. raises: [], tags: [].}-
Возвращает массив
JArray JsonNode.Возвращает
Исходный код Редактироватьdefaultеслиnне являетсяJArray, или еслиnравно null. proc add(father, child: JsonNode) {...}{.raises: [], tags: [].}- Добавляет
childв узел JArrayfather. Исходный код Редактировать proc add(obj: JsonNode; key: string; val: JsonNode) {...}{.raises: [], tags: [].}- Устанавливает поле из
JObject. Исходный код Редактировать proc `%`(s: string): JsonNode {...}{.raises: [], tags: [].}- Универсальный конструктор для данных JSON. Создаёт новый
JString JsonNode. Исходный код Редактировать proc `%`(n: uint): JsonNode {...}{.raises: [], tags: [].}- Универсальный конструктор для данных JSON. Создаёт новый
JInt JsonNode. Исходный код Редактировать proc `%`(n: int): JsonNode {...}{.raises: [], tags: [].}- Универсальный конструктор для данных JSON. Создаёт новый
JInt JsonNode. Исходный код Редактировать proc `%`(n: BiggestUInt): JsonNode {...}{.raises: [], tags: [].}- Универсальный конструктор для данных JSON. Создаёт новый
JInt JsonNode. Исходный код Редактировать proc `%`(n: BiggestInt): JsonNode {...}{.raises: [], tags: [].}- Универсальный конструктор для данных JSON. Создаёт новый
JInt JsonNode. Исходный код Редактировать proc `%`(n: float): JsonNode {...}{.raises: [], tags: [].}- Универсальный конструктор для данных JSON. Создаёт новый
JFloat JsonNode. Исходный код Редактировать proc `%`(b: bool): JsonNode {...}{.raises: [], tags: [].}- Универсальный конструктор для данных JSON. Создаёт новый
JBool JsonNode. Исходный код Редактировать proc `%`(keyVals: openArray[tuple[key: string, val: JsonNode]]): JsonNode {...}{. raises: [], tags: [].}- Универсальный конструктор для данных JSON. Создаёт новый
JObject JsonNodeИсходный код Редактировать proc `%`[T](elements: openArray[T]): JsonNode
- Универсальный конструктор для данных JSON. Создаёт новый
JArray JsonNodeИсходный код Редактировать proc `%`[T](table: Table[string, T] | OrderedTable[string, T]): JsonNode
- Универсальный конструктор для данных JSON. Создаёт новый
JObject JsonNode. Исходный код Редактировать proc `%`[T](opt: Option[T]): JsonNode
- Универсальный конструктор для данных JSON. Создаёт новый
JNull JsonNodeеслиoptпуст, в противном случае делегирует подлежащему значению. Исходный код Редактировать proc `[]=`(obj: JsonNode; key: string; val: JsonNode) {...}{.inline, raises: [], tags: [].}- Устанавливает поле из
JObject. Исходный код Редактировать proc `%`[T: object](o: T): JsonNode
- Конструирует JsonNode из кортежей и объектов. Исходный код Редактировать
proc `%`(o: ref object): JsonNode
- Универсальный конструктор для данных JSON. Создаёт новый
JObject JsonNodeИсходный код Редактировать proc `%`(o: enum): JsonNode
- Создаёт JsonNode, представляющий указанное значение перечисления в виде строки. Создаёт новый
JString JsonNode. Исходный код Редактировать proc `==`(a, b: JsonNode): bool {...}{.raises: [KeyError], tags: [].}- Проверка двух узлов на равенство Исходный код Редактировать
proc hash(n: JsonNode): Hash {...}{.raises: [Exception], tags: [RootEffect].}- Вычисление хэша для узла JSON Исходный код Редактировать
proc hash(n: OrderedTable[string, JsonNode]): Hash {...}{.noSideEffect, raises: [Exception], tags: [RootEffect].}- Исходный код Редактировать
proc len(n: JsonNode): int {...}{.raises: [], tags: [].}
- Если
nявляетсяJArray, оно возвращает количество элементов. ЕслиnявляетсяJObject, оно возвращает количество пар. В противном случае возвращает 0. Источник Редактировать proc `[]`(node: JsonNode; name: string): JsonNode {...}{.inline, raises: [KeyError], tags: [].}- Получает поле из
JObject, которое не должно быть nil. Если значение вnameне существует, возникает исключение KeyError. Источник Редактировать proc `[]`(node: JsonNode; index: int): JsonNode {...}{.inline, raises: [], tags: [].}- Получает узел в
indexв массиве. Результат не определён, еслиindexнаходится вне границ, но при включённых проверках границ массива это приведёт к исключению. Источник Редактировать proc hasKey(node: JsonNode; key: string): bool {...}{.raises: [], tags: [].}- Проверяет, существует ли
keyвnode. Источник Редактировать proc contains(node: JsonNode; key: string): bool {...}{.raises: [], tags: [].}- Проверяет, существует ли
keyвnode. Источник Редактировать proc contains(node: JsonNode; val: JsonNode): bool {...}{.raises: [KeyError], tags: [].}- Проверяет, существует ли
valв массивеnode. Источник Редактировать proc `{}`(node: JsonNode; keys: varargs[string]): JsonNode {...}{.raises: [], tags: [].}-
Проходит по узлу и получает заданное значение. Если какой-либо из ключей не существует, возвращает
nil. Также возвращаетnil, если одна из промежуточных структур данных не является объектом.Эта процедура может использоваться для создания древовидных структур на лету (иногда называемых автовивификацией):
Пример:
var myjson = %* {"parent": {"child": {"grandchild": 1}}} doAssert myjson{"parent", "child", "grandchild"} == newJInt(1)Источник Редактировать proc `{}`(node: JsonNode; index: varargs[int]): JsonNode {...}{.raises: [], tags: [].}- Проходит по узлу и получает заданное значение. Если какой-либо из индексов не существует, возвращает
nil. Также возвращаетnil, если одна из промежуточных структур данных не является массивом. Источник Редактировать proc getOrDefault(node: JsonNode; key: string): JsonNode {...}{.raises: [], tags: [].}- Получает поле из
node. Еслиnodeравно nil или не является объектом, или значение вkeyне существует, возвращает nil Источник Редактировать proc `{}`(node: JsonNode; key: string): JsonNode {...}{.raises: [], tags: [].}- Получает поле из
node. Еслиnodeравно nil или не является объектом, или значение вkeyне существует, возвращает nil Источник Редактировать proc `{}=`(node: JsonNode; keys: varargs[string]; value: JsonNode) {...}{. raises: [KeyError], tags: [].}- Проходит по узлу и пытается установить значение в заданном месте на
value. Если какие-либо ключи отсутствуют, они добавляются. Источник Редактировать proc delete(obj: JsonNode; key: string) {...}{.raises: [KeyError], tags: [].}- Удаляет
obj[key]. Источник Редактировать proc copy(p: JsonNode): JsonNode {...}{.raises: [], tags: [].}- Выполняет глубокую копию
a. Источник Редактировать proc escapeJsonUnquoted(s: string; result: var string) {...}{.raises: [], tags: [].}- Преобразует строку
sв её JSON-представление без кавычек. Добавляет вresult. Источник Редактировать proc escapeJsonUnquoted(s: string): string {...}{.raises: [], tags: [].}- Преобразует строку
sв её JSON-представление без кавычек. Источник Редактировать proc escapeJson(s: string; result: var string) {...}{.raises: [], tags: [].}- Преобразует строку
sв её JSON-представление с кавычками. Добавляет вresult. Источник Редактировать proc escapeJson(s: string): string {...}{.raises: [], tags: [].}- Преобразует строку
sв её JSON-представление с кавычками. Источник Редактировать proc pretty(node: JsonNode; indent = 2): string {...}{.raises: [], tags: [].}-
Возвращает JSON-представление
node, с отступами и на нескольких строках.Аналогично prettyprint в Python.
Пример:
let 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 toUgly(result: var string; node: JsonNode) {...}{.raises: [], tags: [].}-
Преобразует
nodeв его JSON-представление, без учёта удобочитаемости. Предназначено для повышения производительности преобразования строки$.JSON-представление хранится в переданном
resultЭто обеспечивает более высокую эффективность, чем процедура
Источник Редактироватьpretty, так как не пытается отформатировать результирующий JSON для повышения удобочитаемости. proc `$`(node: JsonNode): string {...}{.raises: [], tags: [].}- Преобразует
nodeв его JSON-представление на одной строке. Источник Редактировать proc parseJson(s: Stream; filename: string = ""; rawIntegers = false; rawFloats = false): JsonNode {...}{.raises: [IOError, OSError, IOError, OSError, JsonParsingError, ValueError, Exception], tags: [ReadIOEffect, WriteIOEffect].}- Парсит из потока
sвJsonNode.filenameнеобходим только для красивых сообщений об ошибках. Еслиsсодержит дополнительные данные, он подниметJsonParsingError. Этот потокsзакрывается после завершения. ЕслиrawIntegersравно true, целые литералы не будут преобразовываться в полеJInt, а будут сохранены как исходные числа с помощьюJString. ЕслиrawFloatsравно true, числа с плавающей точкой не будут преобразовываться в полеJFloat, а будут сохранены как исходные числа с помощьюJString. Источник Редактировать proc parseJson(buffer: string; rawIntegers = false; rawFloats = false): JsonNode {...}{. raises: [IOError, OSError, JsonParsingError, ValueError, Exception], tags: [ReadIOEffect, WriteIOEffect].}- Парсит JSON из
buffer. Еслиbufferсодержит дополнительные данные, он подниметJsonParsingError. ЕслиrawIntegersравно true, целые литералы не будут преобразовываться в полеJInt, а будут сохранены как исходные числа с помощьюJString. ЕслиrawFloatsравно true, числа с плавающей точкой не будут преобразовываться в полеJFloat, а будут сохранены как исходные числа с помощьюJString. Источник Редактировать proc parseFile(filename: string): JsonNode {...}{. raises: [IOError, OSError, JsonParsingError, ValueError, Exception], tags: [ReadIOEffect, WriteIOEffect].}- Парсит
fileвJsonNode. Еслиfileсодержит дополнительные данные, он подниметJsonParsingError. Источник Редактировать proc to[T](node: JsonNode; t: typedesc[T]): T
-
Десериализует указанный узел в тип объекта, указанный в параметре.
Известные ограничения:
- Гетерогенные массивы не поддерживаются.
- Множества в вариантах объектов не поддерживаются.
- Аннотации `not nil` не поддерживаются.
Пример:
let 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]Источник Редактировать
Итераторы
iterator items(node: JsonNode): JsonNode {...}{.raises: [], tags: [].}- Итератор для элементов
node.nodeдолжен быть JArray. Исходный код Редактировать iterator mitems(node: var JsonNode): var JsonNode {...}{.raises: [], tags: [].}- Итератор для элементов
node.nodeдолжен быть JArray. Элементы можно изменять. Исходный код Редактировать iterator pairs(node: JsonNode): tuple[key: string, val: JsonNode] {...}{.raises: [], tags: [].}- Итератор для дочерних элементов
node.nodeдолжен быть JObject. Исходный код Редактировать iterator keys(node: JsonNode): string {...}{.raises: [], tags: [].}- Итератор для ключей в
node.nodeдолжен быть JObject. Исходный код Редактировать iterator mpairs(node: var JsonNode): tuple[key: string, val: var JsonNode] {...}{. raises: [], tags: [].}- Итератор для дочерних элементов
node.nodeдолжен быть JObject. Значения могут быть изменены Исходный код Редактировать iterator parseJsonFragments(s: Stream; filename: string = ""; rawIntegers = false; rawFloats = false): JsonNode {...}{.raises: [ IOError, OSError, IOError, OSError, JsonParsingError, ValueError, Exception], tags: [ReadIOEffect, WriteIOEffect].}- Парсит поток
sвJsonNodes.filenameнужен только для удобных сообщений об ошибках. Фрагменты JSON разделены пробелами. Это может быть существенно быстрее, чем аналогичный циклfor x in splitWhitespace(s): yield parseJson(x). Закрывает потокsпосле завершения. ЕслиrawIntegerstrue, целые числа не будут преобразованы в полеJInt, а будут сохранены как исходные числа черезJString. ЕслиrawFloatstrue, числа с плавающей запятой не будут преобразованы в полеJFloat, а будут сохранены как исходные числа черезJString. Исходный код Редактировать
Макросы
macro `%*`(x: untyped): untyped
- Преобразует выражение в JsonNode напрямую, без необходимости указывать
%для каждого элемента. Исходный код Редактировать macro isRefSkipDistinct(arg: typed): untyped
- Только для внутреннего использования, не использовать Исходный код Редактировать
Шаблоны
template `%`(j: JsonNode): JsonNode
- Исходный код Редактировать
Экспорт
- $, $, $, $, $, $, JsonEventKind, JsonError, JsonParser, JsonKindError, open, open, open, open, open, close, close, close, close, str, getInt, getFloat, kind, kind, getColumn, getLine, getFilename, errorMsg, errorMsgExpected, next, JsonParsingError, raiseParseErr, nimIdentNormalize
© 2006–2021 Andreas Rumpf
Licensed under the MIT License.
https://nim-lang.org/docs/json.html