Статьи

Документация

Дополнительно

JSON/CBOR

Модуль stappler_data предназначен для работы с нетипизированными форматами JSON, CBOR, форматами urlencoded и собственным форматом Serenity Query.

Модуль предоставляет контейнер нетипизированных значений Value в вариантах для обоих интерфейсов памяти.

Для чтения данных предназначены функции:

  • data::read
  • data::readFile

Функции определяют исходный формат автоматически.

Для записи данных:

  • data::write
  • data::save - сохраняет в файл
  • data::toString - записывает в строку (если возможно для формата

Формат записи определяется типом data::EncodeFormat.

Формат характеризуется типом и сжатием;

Тип:

  • Json - JSON
  • Pretty - человекочитаемый JSON
  • Cbor - CBOR (http://cbor.io/, http://tools.ietf.org/html/rfc7049)
  • DefaultFormat - на выбор SDK (обычно CBOR)
  • Serenity - Serenity Query
  • SerenityPretty - человекочитаемый Serenity Query
  • PrettyTime - человекочитаемый JSON с декодированными метками времени SDK

Сжатие:

  • NoCompression
  • LZ4Compression
  • LZ4HCCompression
  • Brotli - доступно, если подключен stappler_brotli_lib

Пример работы с Value:

// создание массива объектов
Value arr({
    Value({
        pair("one", Value(1)),
        pair("two", Value(2)),
    }),
    Value({
        pair("one", Value(3)),
        pair("two", Value(4)),
    })
});

// перебор массива
for (auto &it : arr.asArray()) {
    for (auto &obj : it.asDict()) {
        std::cout << "Key: " << obj.first << " Value: " << data::toString<Interface>(obj.second) << "\n"
    }
}

Сжатие

Интерфейс сжатия можно использовать без Value функциями

  • data::compress - сжимает в блок данных из интерфейса памяти, блок автоматически будет распознан при декомпрессии
  • data::getCompressBounds - возвращает максимальный размер буфера для сжатия
  • data::compressData - выполняет сжатие буфера в целевой буфер
  • data::writeCompressionMark - записыает 4-байтную метку сжатия, по которой система распознаёт формат
  • data::decompress - в полном варианте расшифровывает сжатый блок в буфер с известным размером, в малом - в блок интерфейса памяти
  • data::getDecompressedSize - получает размер данных до сжатия

Serenity Query

Формат строки запроса Serenity нужен для компактного определения json-подобных структур в строке запроса без дополнительного кодирования. Схож по задачам с GraphQL.

Допустимые специальные символы в строке запроса: `/ ? : @ - . _ ~ ! $ & ' ( ) * + , ; =``

Допустимые символы в токенах: 0-9 A-Z a-z / ? @ - . _ ! $ ' * +

Запрещены в токенах: : & ( ) , ; = ~

В реальной работе пробельные символы недопустимы, они используются для демонстрации логики формата человеку.

Для кодирования токенов можно использовать процентное кодирование, как в обычных URL. Процентно-кодированные символы не считаются спецсимволами.

Зарезервированные токены: n, t, f, null true false inf +inf -inf nan

Зарезервированные токены можно использовать в качестве обычных, если использовать процентное кодирование

Пример кодирования: http://localhost/index?(field:value;arrayField:array1,array2,array3;dictField:(field1:value1;field2:value2))

Запрос

(
    field: value;
    arrayField: array1, array2, array3;
    flagField;
    dictField (
        field1: value1;
        field2: value2
    )
)

интерпретируется как:

{
    “field”: “value”,
    “arrayField”: [“array1”, ”array2”, ”array3”],
    “flagField”: true,
    “dictField”: {
        “field1”: “value1”,
        “field2”: “value2”
    }
}

Первичный объект всегда должен присутствовать и интерпретироваться как объект/словарь.

Токены на позициях, соответствующих именам полей объекта всегда интерпретируются как строки. В других позициях тип определяется автоматически. Поддерживаются стандартные JSON-типы (float, integer, bool, null, string) и тип bytes (кодируется префиксом ~ перед токеном и процентным кодированием байт).

Явное объявление массива: ~(array1, ~(subarray1, subarray2, ~(subsubarrayItem)), array3)

Типы

Базовые:

  • true, t - bool true
  • false, f - bool false
  • null, n - null

Числовые - Аналогично JSON

Строки

Строки не выделяются кавычками, могут содержать символы 0-9 A-Z a-z / ? @ - . _ ! $ ' * +. Другие символы кодируются с помощью процентного кодирования. Для определения строки, совпадающей с зарезервированным токеном или выглядящей как число нужно использовать процентное кодирование, как минимум, первого символа.

Токены, начинающиеся с числа или + - могут быть распознаны как строки, если не распознаны, как числа.

Бинарные данные

Кодируются аналогично строкам, с префиксом ~. Реализация должна учитывать, что бинарный блок может содержать процентно-кодированные нечитаемые и специальные символы, включая ~%00.

Объекты/Словари

Объекты кодируются с помощью круглых скобок и ; в качестве разделителя

Типовое кодирование объекта выглядит так: (field:value;arrayField:array1,array2,array3;dictField:(field1:value1;field2:value2);flagField:true)

Некоторые части могут быть опущены:

  • ; после закрывающей скобки объекта
  • : перед открывающей скобкой объекта
  • :true, :t для полей-флагов

В итоге, строка будет выглядеть так: (field:value;arrayField:array1,array2,array3;dictField(field1:value1;field2:value2)flagField)

(
    field : value;
    arrayField : array1, array2, array3;
    dictField (
        field1 : value1;
        field2 : value2
    )
    flagField
)

Массивы

Массивы могут кодироваться двумя способами.

Вложенное кодирование массивов может использоваться для описания массива как поля объекта. В таком случае элементы массива перечисляются через запятую без других специальных символов. Для интерпретации вложенного массива нужны, как минимум, два значения.

(
    arrayField : array1, {field:value), ~(val1, val2), false;
)

Универсальное кодирование массивов используется в любом месте, в том числе, для определения массивов внутри других массивов. Массивы кодируются внутри конструкции ~( ), через запятую.

(
arrayField : ~(array1, {field:value), ~(val1, val2), false);
)