Формальное описание синтаксиса атрибута Citeck Records ======================================================== .. contents:: :depth: 3 Терминология -------------- * **Контекст** - область, которая выделена с помощью скобок или кавычек ``{}``, ``[]``, ``()``, ``""``, ``''`` или не выделена ничем (корневая область или корневой контекст); * **Алиас** - псевдоним для атрибута. Пример: в конструкции ``someAlias:name`` someAlias является алиасом и возможный результат вычисления - ``someAlias:"Договор №2"``; * **Экранирование символа** - добавление перед символом знака ``\``. Необходимо в тех случаях, когда спец-символ должен быть обработан как обычный символ; * **Спец-символ** - символ, который в определенном контексте имеет специальное значение. * **Скаляр** - конечный атрибут, который не может содержать вложенных атрибутов. Может быть одним из ``?id``, ``?str``, ``?disp``, ``?num``, ``?assoc``, ``?localId``, ``?bool``, ``?json``. .. note:: 1. Экранирование спец-символов необходимо только в текущем контексте и не требуется во вложенных контекстах. Описание ---------- Общий вид атрибута:: path0[].path1{INNER}|proc0(arg0,arg1)|proc1(arg0,arg1) (1) ``path0[].path1`` - это путь из атрибутов. Элементы пути объединяются через точку. Если точка является частью имени атрибута, то её следует экранировать. Все атрибуты в пути кроме последнего имеют ровно один внутренний атрибут без пост-процессоров и алиаса. Последний атрибут в пути может иметь любое количество вложенных атрибутов, но не имеет алиаса. Все атрибуты в пути кроме первого не имеют пост-процессоров. Первый атрибут в пути может иметь любое количество пост-процессоров, которые указываются в конце после ``{INNER}``. Любой элемент пути из атрибутов может иметь окончание ``[]``, которое при наличии означает, что атрибут множественный. ``{INNER}`` содержит вложенные атрибуты с алиасами, которые разделены через запятую. Алиас не обязателен. Если он отсутствует, то для результата используется первое имя в пути атрибутов. Пример значения ``{INNER}``:: {alias0:attribute0,alias1:attribute1,attribute2} В **aliasN** спец-символами являются ``,`` и ``:``. Вместо **attributeN** допускается синтаксис (1), но c экранированием запятых ``,`` и если отсутствует алиас, то следует экранировать ``:`` (см. Примечание 1). Если алиас равен первому элементу в пути атрибутов, то это равнозначно отсутствию алиаса. Вместо ``{INNER}`` при наличии только одного вложенного атрибута без алиаса и процессоров допускается запись без фигурных скобок. В таком случае если вложенный атрибут не является скаляром, то перед ним добавляется точка. Перед скаляром ничего не добавляется т.к. он уже содержит разделительный символ ``?``. Примеры:: name?str == name{?str} name.title?str == name{title{?str}} Если атрибут заканчивается на скаляр ``?disp`` (``att0?disp`` или ``att0{?disp}``), то допускается опустить окончание ``?disp`` в атрибуте т.к. это скаляр по-умолчанию. Пример:: name?disp == name При описании атрибута допускается использование пост-процессоров, которые вызываются с результатом вычисления атрибута:: proc0(arg0,arg1) * **procN** - имя пост-процессора; * **argN** - аргументы, которые отделяются друг от друга запятыми. Допускаются значения аналогичные формату json - https://www.json.org/json-en.html , но с возможностью использовать для строк одинарные кавычки вместо двойных; Пост-процессоры объединяются через символ ``|`` и выполняются слева направо аналогично unix pipeline. Пост-процессоры могут быть частью любого атрибута на любом уровне вложенности. Для пост-процессора с типом "or" доступен дополнительный синтаксис с использованием ``!``. Возможные варианты значения после ``!``: 1. Значение в двойных или одинарных кавычках означает константную строку; (``some!'constant' == some|or('constant')``) 2. При отсутствии значения парсер подбирает нужный аргумент в зависимости от скаляра перед знаком ``!``: * ?bool! -> ``false`` * ?json! -> ``{}``; * ?num! -> ``0``; * иначе -> ``""``. 3. null означает пустое значение; (``some!null == some|or(null)``) 4. true или false - булево значение; (``some!true == some|or(true)``) 5. Если первый символ число - числовое значение; (``some!123 == some|or(123)``) 6. Если ни один из вышестоящих вариантов не подошел, то считается, что указано имя атрибута, который нужно вернуть в случае если результат вычисления атрибута до ``!`` оказался null; (``some!other == some|or('a:other')``) Между частями атрибута (алиас, путь, вложенные атрибуты, пост-процессоры, аргументы) допускается использование любого количества пробельных символов (``\n``, ``\t``, ``\r``, :literal:`\ `). Модель атрибута:: SchemaAtt { alias: String, name: String, multiple: Boolean, inner: List, processors: List } Модель пост-процессора:: AttProcDef { type: String, arguments: List } * **DataValue** - любой json тип - https://www.json.org/json-en.html