Spec-Zone.ru › Nim

std/json

SourceEdit

Этот модуль реализует простой, высокопроизводительный парсер JSON. JSON (JavaScript Object Notation) — это лёгкий формат обмена данными, удобный для чтения и записи человеком (в отличие от XML). Он легко парсируется и генерируется машинами. JSON основан на подмножестве языка программирования JavaScript, Стандарт ECMA-262 3-го издания — декабрь 1999 года.

См. также

  • std/parsejson
  • std/jsonutils
  • std/marshal
  • std/jscore

Обзор

Парсинг JSON

JSON часто поступает в вашу программу (через API или файл) в виде string. Первый шаг — преобразовать его из сериализованной формы в структуру вложенных объектов, называемую JsonNode.

Процедура parseJson принимает строку, содержащую JSON, и возвращает объект JsonNode. Это объект-вариант, и он может быть JObject, JArray, JString, JInt, JFloat, JBool или JNull. Вид этого объекта-варианта проверяется с помощью доступа kind.

Для JsonNode, чей вид JObject, вы можете получить доступ к его полям с помощью оператора [] . Следующий пример демонстрирует это:

import std/json

let jsonNode = parseJson("""{"key": 3.14}""")

doAssert jsonNode.kind == JObject
doAssert jsonNode["key"].kind == JFloat

Чтение значений

После получения JsonNode, извлечение значений можно выполнить, используя одну из вспомогательных процедур, которые включают:

  • getInt
  • getFloat
  • getStr
  • getBool

Для получения значения "key" вы можете сделать следующее:

import std/json

let jsonNode = parseJson("""{"key": 3.14}""")

doAssert jsonNode["key"].getFloat() == 3.14

Важно: Оператор [] вызовет исключение, если указанное поле не существует.

Обработка необязательных ключей

Используя оператор {} вместо [], он вернёт nil при отсутствии поля. Семейство процедур get вернёт значение по умолчанию для типа при вызове на 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

Использование значений по умолчанию

Вспомогательные функции семейства get также принимают дополнительный параметр, который позволяет использовать значение по умолчанию, если значение ключа 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 {}

Распаковка

Помимо чтения динамических данных, Nim также может распаковывать JSON напрямую в тип с помощью макроса to.

Примечание: Используйте Option для ключей, которые иногда отсутствуют в ответах JSON, и обрамляйте ключи с зарезервированным ключевым словом в обратные кавычки.

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"

Создание JSON

Этот модуль также может использоваться для удобного создания JSON с помощью оператора %*:

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

См. также: std/jsonutils для привязываемой сериализации/десериализации JSON произвольных типов.

Пример:

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}"""

Импорты

hashes, tables, strutils, lexbase, streams, macros, parsejson, options, since

Типы

JsonNode = ref JsonNodeObj
Узел JSON Source Edit
JsonNodeKind = enum
  JNull, JBool, JInt, JFloat, JString, JObject, JArray
Возможные типы узлов JSON Source Edit
JsonNodeObj {.acyclic.} = object
  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]
Source Edit

Процедуры

proc `$`(node: JsonNode): string {....raises: [], tags: [], forbids: [].}
Преобразует node в его JSON представление на одной строке. Исходный код Редактировать
proc `%`(b: bool): JsonNode {....raises: [], tags: [], forbids: [].}
Общий конструктор для JSON данных. Создаёт новый JBool JsonNode. Исходный код Редактировать
proc `%`(keyVals: openArray[tuple[key: string, val: JsonNode]]): JsonNode {.
    ...raises: [], tags: [], forbids: [].}
Общий конструктор для JSON данных. Создаёт новый JObject JsonNode. Исходный код Редактировать
proc `%`(n: BiggestInt): JsonNode {....raises: [], tags: [], forbids: [].}
Общий конструктор для JSON данных. Создаёт новый JInt JsonNode. Исходный код Редактировать
proc `%`(n: BiggestUInt): JsonNode {....raises: [], tags: [], forbids: [].}
Общий конструктор для JSON данных. Создаёт новый JInt JsonNode. Исходный код Редактировать
proc `%`(n: float): JsonNode {....raises: [], tags: [], forbids: [].}
Общий конструктор для JSON данных. Создаёт новый JFloat JsonNode.

Пример:

assert $(%[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: [].}
Общий конструктор для JSON данных. Создаёт новый JInt JsonNode. Исходный код Редактировать
proc `%`(n: uint): JsonNode {....raises: [], tags: [], forbids: [].}
Общий конструктор для JSON данных. Создаёт новый JInt JsonNode. Исходный код Редактировать
proc `%`(o: enum): JsonNode
Создаёт JsonNode, представляющий указанное значение перечисления в виде строки. Создаёт новый JString JsonNode. Исходный код Редактировать
proc `%`(o: ref object): JsonNode
Общий конструктор для JSON данных. Создаёт новый JObject JsonNode Исходный код Редактировать
proc `%`(s: string): JsonNode {....raises: [], tags: [], forbids: [].}
Общий конструктор для JSON данных. Создаёт новый JString JsonNode. Исходный код Редактировать
proc `%`[T: object](o: T): JsonNode
Создаёт JsonNode из кортежей и объектов. Исходный код Редактировать
proc `%`[T](elements: openArray[T]): JsonNode
Общий конструктор для JSON данных. Создаёт новый JArray JsonNode Исходный код Редактировать
proc `%`[T](opt: Option[T]): JsonNode
Общий конструктор для JSON данных. Создаёт новый JNull JsonNode, если opt пусто, иначе делегирует подлежащему значению. Исходный код Редактировать
proc `%`[T](table: Table[string, T] | OrderedTable[string, T]): JsonNode
Общий конструктор для JSON данных. Создаёт новый JObject JsonNode. Исходный код Редактировать
proc `==`(a, b: JsonNode): bool {.noSideEffect, ...raises: [], tags: [RootEffect],
                                  forbids: [].}
Проверка двух узлов на равенство Исходный код Редактировать
proc `[]`(node: JsonNode; index: BackwardsIndex): JsonNode {.inline, ...raises: [],
    tags: [], forbids: [].}

Получение узла по array.len-i в массиве через оператор ^.

Например, j[^i] — это сокращение для j[j.len-i].

Пример:

let
  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: [].}
Получение узла по index в массиве. Результат неопределён, если index выходит за границы, но при включённых проверках границ массива он приведёт к исключению. Исходный код Редактировать
proc `[]`(node: JsonNode; name: string): JsonNode {.inline, ...raises: [KeyError],
    tags: [], forbids: [].}
Получение поля из JObject, которое не должно быть nil. Если значение по name не существует, генерируется KeyError. Исходный код Редактировать
proc `[]`[U, V](a: JsonNode; x: HSlice[U, V]): JsonNode

Операция среза для JArray.

Возвращает включительный диапазон [a[x.a], a[x.b]]:

Пример:

import std/json
let arr = %[0,1,2,3,4,5]
doAssert arr[2..4] == %[2,3,4]
doAssert arr[2..^2] == %[2,3,4]
doAssert arr[^4..^2] == %[2,3,4]
Исходный код Редактировать
proc `[]=`(obj: JsonNode; key: string; val: JsonNode) {.inline, ...raises: [],
    tags: [], forbids: [].}
Установка поля в JObject. Исходный код Редактировать
proc add(father, child: JsonNode) {....raises: [], tags: [], forbids: [].}
Добавляет child в узел JArray father. Исходный код Редактировать
proc add(obj: JsonNode; key: string; val: JsonNode) {....raises: [], tags: [],
    forbids: [].}
Установка поля в JObject. Исходный код Редактировать
proc contains(node: JsonNode; key: string): bool {....raises: [], tags: [],
    forbids: [].}
Проверка, существует ли key в node. Исходный код Редактировать
proc contains(node: JsonNode; val: JsonNode): bool {....raises: [],
    tags: [RootEffect], forbids: [].}
Проверка, существует ли val в массиве node. Исходный код Редактировать
proc copy(p: JsonNode): JsonNode {....raises: [], tags: [], forbids: [].}
Выполняет глубокую копию p. Исходный код Редактировать
proc delete(obj: JsonNode; key: string) {....raises: [KeyError], tags: [],
    forbids: [].}
Удаляет obj[key]. Исходный код Редактировать
proc escapeJson(s: string): string {....raises: [], tags: [], forbids: [].}
Преобразует строку s в её JSON представление с кавычками. Исходный код Редактировать
proc escapeJson(s: string; result: var string) {....raises: [], tags: [],
    forbids: [].}
Преобразует строку s в её JSON представление с кавычками. Добавляет в result. Исходный код Редактировать
proc escapeJsonUnquoted(s: string): string {....raises: [], tags: [], forbids: [].}
Преобразует строку s в её JSON представление без кавычек. Исходный код Изменить
proc escapeJsonUnquoted(s: string; result: var string) {....raises: [], tags: [],
    forbids: [].}
Преобразует строку s в её JSON представление без кавычек. Добавляет к result. Исходный код Изменить
proc getBiggestInt(n: JsonNode; default: BiggestInt = 0): BiggestInt {.
    ...raises: [], tags: [], forbids: [].}

Возвращает значение BiggestInt из JInt JsonNode.

Возвращает default если n не является JInt, или если n равно null.

Исходный код Изменить
proc getBool(n: JsonNode; default: bool = false): bool {....raises: [], tags: [],
    forbids: [].}

Возвращает значение bool из JBool JsonNode.

Возвращает default если n не является JBool, или если n равно null.

Исходный код Изменить
proc getElems(n: JsonNode; default: seq[JsonNode] = @[]): seq[JsonNode] {.
    ...raises: [], tags: [], forbids: [].}

Возвращает массив из JArray JsonNode.

Возвращает default если n не является JArray, или если n равно null.

Исходный код Изменить
proc getFields(n: JsonNode; default = initOrderedTable[string, JsonNode](2)): OrderedTable[
    string, JsonNode] {....raises: [], tags: [], forbids: [].}

Возвращает пары ключ-значение из JObject JsonNode.

Возвращает default если n не является JObject, или если n равно null.

Исходный код Изменить
proc getFloat(n: JsonNode; default: float = 0.0): float {....raises: [], tags: [],
    forbids: [].}

Возвращает значение float из JFloat JsonNode.

Возвращает default если n не является JFloat или JInt, или если n равно null.

Исходный код Изменить
proc getInt(n: JsonNode; default: int = 0): int {....raises: [], tags: [],
    forbids: [].}

Возвращает значение int из JInt JsonNode.

Возвращает default если n не является JInt, или если n равно null.

Исходный код Изменить
proc getOrDefault(node: JsonNode; key: string): JsonNode {....raises: [], tags: [],
    forbids: [].}
Получает поле из node Если node равно null или не является объектом, или поле по key не существует, возвращает null Исходный код Изменить
proc getStr(n: JsonNode; default: string = ""): string {....raises: [], tags: [],
    forbids: [].}

Возвращает строковое значение из JString JsonNode.

Возвращает default если n не является JString, или если n равно null.

Исходный код Изменить
proc hash(n: JsonNode): Hash {.noSideEffect, ...raises: [Exception],
                               tags: [RootEffect], forbids: [].}
Вычисляет хеш для узла JSON Исходный код Изменить
proc hash(n: OrderedTable[string, JsonNode]): Hash {.noSideEffect,
    ...raises: [Exception], tags: [RootEffect], forbids: [].}
Исходный код Изменить
proc hasKey(node: JsonNode; key: string): bool {....raises: [], tags: [],
    forbids: [].}
Проверяет существование key в node Исходный код Изменить
proc len(n: JsonNode): int {....raises: [], tags: [], forbids: [].}
Если n является массивом, возвращает количество элементов. Если n является объектом, возвращает количество пар. Иначе возвращает 0. Исходный код Изменить
proc newJArray(): JsonNode {....raises: [], tags: [], forbids: [].}
Создаёт новый массив JArray JsonNode Исходный код Изменить
proc newJBool(b: bool): JsonNode {....raises: [], tags: [], forbids: [].}
Создаёт новый булевый JBool JsonNode. Исходный код Изменить
proc newJFloat(n: float): JsonNode {....raises: [], tags: [], forbids: [].}
Создаёт новый JFloat JsonNode. Исходный код Изменить
proc newJInt(n: BiggestInt): JsonNode {....raises: [], tags: [], forbids: [].}
Создаёт новый JInt JsonNode. Исходный код Изменить
proc newJNull(): JsonNode {....raises: [], tags: [], forbids: [].}
Создаёт новый JNull JsonNode. Исходный код Изменить
proc newJObject(): JsonNode {....raises: [], tags: [], forbids: [].}
Создаёт новый объект JObject JsonNode Исходный код Изменить
proc newJString(s: string): JsonNode {....raises: [], tags: [], forbids: [].}
Создаёт новую строку JString JsonNode. Исходный код Изменить
proc parseFile(filename: string): JsonNode {.
    ...raises: [IOError, OSError, JsonParsingError, ValueError],
    tags: [ReadIOEffect, WriteIOEffect], forbids: [].}
Парсит file в JsonNode. Если file содержит дополнительные данные, будет выброшено исключение JsonParsingError. Исходный код Изменить
proc parseJson(buffer: string; rawIntegers = false; rawFloats = false): JsonNode {.
    ...raises: [IOError, OSError, JsonParsingError, ValueError],
    tags: [ReadIOEffect, WriteIOEffect], forbids: [].}
Парсит JSON из buffer. Если buffer содержит дополнительные данные, будет выброшено исключение JsonParsingError. Если rawIntegers true, целочисленные литералы не будут преобразовываться в поле JInt, а будут сохранены как исходные числа через JString. Если rawFloats true, литералы с плавающей точкой не будут преобразовываться в поле JFloat, а будут сохранены как исходные числа через JString. Исходный код Изменить
proc parseJson(s: Stream; filename: string = ""; rawIntegers = false;
               rawFloats = false): JsonNode {.
    ...raises: [IOError, OSError, IOError, OSError, JsonParsingError, ValueError],
    tags: [ReadIOEffect, WriteIOEffect], forbids: [].}
Парсит из потока s в JsonNode. filename необходимо только для красивых сообщений об ошибках. Если s содержит дополнительные данные, будет выброшено исключение JsonParsingError. Закрывает поток s после завершения. Если rawIntegers true, целочисленные литералы не будут преобразовываться в поле JInt, а будут сохранены как исходные числа через JString. Если rawFloats true, литералы с плавающей точкой не будут преобразовываться в поле JFloat, а будут сохранены как исходные числа через JString. Исходный код Изменить
proc pretty(node: JsonNode; indent = 2): string {....raises: [], tags: [],
    forbids: [].}

Возвращает 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 to[T](node: JsonNode; t: typedesc[T]): T

Распаковывает указанный узел в тип объекта.

Известные ограничения:

  • Гетерогенные массивы не поддерживаются.
  • Множества в вариантах объектов не поддерживаются.
  • Аннотации не 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]
Исходный код Изменить
proc toUgly(result: var string; node: JsonNode) {....raises: [], tags: [],
    forbids: [].}

Преобразует node в его JSON-представление, не заботясь о удобочитаемости. Предназначено для повышения производительности преобразования строки в $.

JSON-представление хранится в переданной result

Это обеспечивает более высокую эффективность, чем процедура pretty, так как она не пытается отформатировать результирующий JSON для удобочитаемости.

Исходный код Изменить
proc `{}`(node: JsonNode; index: varargs[int]): JsonNode {....raises: [], tags: [],
    forbids: [].}
Перебирает узел и получает заданное значение. Если какой-либо из индексов не существует, возвращает nil. Также возвращает nil если одна из промежуточных структур данных не является массивом. Исходный код Изменить
proc `{}`(node: JsonNode; key: string): JsonNode {....raises: [], tags: [],
    forbids: [].}
Получает поле из node. Если node имеет значение nil или не является объектом, или значение по key не существует, возвращает nil Исходный код Изменить
proc `{}`(node: JsonNode; keys: varargs[string]): JsonNode {....raises: [],
    tags: [], forbids: [].}

Перебирает узел и получает заданное значение. Если какой-либо из ключей не существует, возвращает nil. Также возвращает nil если одна из промежуточных структур данных не является объектом.

Эта процедура может использоваться для создания древовидных структур на лету (иногда называемых автовивификацией):

Пример:

var myjson = %* {"parent": {"child": {"grandchild": 1}}}
doAssert myjson{"parent", "child", "grandchild"} == newJInt(1)
Исходный код Изменить
proc `{}=`(node: JsonNode; keys: varargs[string]; value: JsonNode) {.
    ...raises: [KeyError], tags: [], forbids: [].}
Перебирает узел и пытается установить значение в заданном месте на value. Если какие-либо из ключей отсутствуют, они добавляются. Исходный код Изменить

Итераторы

iterator items(node: JsonNode): JsonNode {....raises: [], tags: [], forbids: [].}
Итератор для элементов node. node должен быть JArray. Исходный код Изменить
iterator keys(node: JsonNode): string {....raises: [], tags: [], forbids: [].}
Итератор для ключей в node. node должен быть JObject. Исходный код Изменить
iterator mitems(node: var JsonNode): var JsonNode {....raises: [], tags: [],
    forbids: [].}
Итератор для элементов node. node должен быть JArray. Элементы могут быть изменены. Исходный код Изменить
iterator mpairs(node: var JsonNode): tuple[key: string, val: var JsonNode] {.
    ...raises: [], tags: [], forbids: [].}
Итератор для дочерних элементов node. node должен быть JObject. Значения могут быть изменены Исходный код Изменить
iterator pairs(node: JsonNode): tuple[key: string, val: JsonNode] {....raises: [],
    tags: [], forbids: [].}
Итератор для дочерних элементов node. node должен быть JObject. Исходный код Изменить
iterator parseJsonFragments(s: Stream; filename: string = "";
                            rawIntegers = false; rawFloats = false): JsonNode {.
    ...raises: [IOError, OSError, IOError, OSError, JsonParsingError, ValueError],
    tags: [ReadIOEffect, WriteIOEffect], forbids: [].}
Парсит из потока s в JsonNodes. filename нужен только для красивых сообщений об ошибках. JSON-фрагменты разделены пробелами. Это может быть значительно быстрее, чем аналогичный цикл for x in splitWhitespace(s): yield parseJson(x). Закрывает поток s после завершения. Если rawIntegers имеет значение true, целочисленные литералы не будут преобразовываться в поле JInt, а будут сохраняться как исходные числа через JString. Если rawFloats имеет значение true, литералы с плавающей запятой не будут преобразовываться в поле JFloat, а будут сохраняться как исходные числа через JString. Исходный код Изменить

Макросы

macro `%*`(x: untyped): untyped
Преобразует выражение в JsonNode напрямую, без необходимости указывать % для каждого элемента. Исходный код Изменить
macro isRefSkipDistinct(arg: typed): untyped
Только внутреннее использование, не использовать Исходный код Изменить

Шаблоны

template `%`(j: JsonNode): JsonNode
Исходный код Изменить

© 2006–2024 Andreas Rumpf
Licensed under the MIT License.
https://nim-lang.org/docs/json.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API