Структурированное представление
Все структурированные представления (форматы) можно условно разделить на два типа:
- Иерархические (XML, JSON) - один текстовый файл, а информация для групп объектов помещается в виде списка внутрь информации для групп-родителей.
- Плоские (DBF, CSV, XLS, TABLE) - по одному файлу-таблице для каждой группы объектов, при этом для каждой группы объектов с вложенностью больше единицы в ее таблице должна присутствовать колонка с именем
parent
, содержащая номер "верхней" строки в таблице группы-родителя.
Работа с плоскими форматами при глубине иерархии больше единицы не очень удобна (из-за необходимости поддержки дополнительной колонки), поэтому, как правило, плоские форматы используются только для работы с простыми формами (с глубиной иерархии меньше единицы). В остальных случаях, как правило, используются иерархические форматы.
Форматы также делятся на:
- human-readable (текстовые) и бинарные. Все иерархические форматы - human-readable, плоские могут быть как бинарными (DBF, TABLE, XLS), так и human-readable (CSV). Для human-readable форматов можно / нужно задавать кодировку (по умолчанию UTF-8).
- стандартизированные и внутренние. На текущий момент поддерживается ровно один внутренний формат - TABLE (таблица значений), все остальные форматы - стандартизированные. Файлы внутренних форматов специальным образом обрабатываются в некоторых операциях интеграции (например, в обращении к SQL). Кроме того, внутренние форматы можно использовать для общения lsFusion-систем друг с другом.
В текущей реализации платформы группы-в-колонки в структурированном представлении игнорируются.
При построении иерархии групп объектов в структурированном представлении группы объектов, для которых при открытии формы были переданы все объекты, игнорируются (как если бы этих групп объектов не было).
Если в структурированном представлении группа отображения свойства задается явно, то эта группа должна быть не раньше, чем определенная по умолчанию (если заданная группа будет раньше, то все равно будет использована группа отображения по умолчанию)
Имя экспорта / импорта
Имя свойства на форме, которое будет использовано при экспорте / импорте, можно задать явно при помощи соответствующей опции (EXTID
). Если этого не сделать, то в качестве имени экспорта / импорта будет использовано имя свойства на форме. Если и оно не задано, то именем экспорта / импорта будет имя самого свойства (без добавления в конец объектов-параметров, как это делается в других механизмах - отчетах, настройке дизайна интерактивного представления и т.п.). Аналогичным образом определяется имена экспорта / импорта групп объектов и групп свойств.
Для формы (а точнее ее пустой группы объектов) из-за особенностей грамматики опция задания ее имени импорта / экспорта называется FORMEXTID
(а не EXTID
)
В отличии от имен свойств на форме, имена экспорта / импорта (EXTID
) свойств могут совпадать, если они находятся в разных узлах иерархии (то есть разных группах объектов / свойств). Тоже самое касается имен экспорта / импорта групп объектов и групп свойств.
Иерархическое представление
Перед тем как непосредственно приступить к экспорту / импорту формы, платформа строит иерархию свойств, групп объектов / свойств следующим образом:
- Строится иерархия свойств / групп объектов в соответствии с иерархией групп объектов и группами отображения свойств : группа отображения свойства считается родителем этого свойства, иерархия групп объектов сохраняется.
- Затем для каждой группы объектов
X
:- для всех потомков
X
определяются группы свойств, которым они принадлежат, после чего эти группы свойств и их предки автоматически включаются в иерархию. При этом:- родителями потомков
X
становятся группы свойств, которым они принадлежат - иерархия групп свойств сохраняется
- родителями самых верхних (то есть без родителей) использованных групп свойств становится группа объектов
X
.
- родителями потомков
- для всех потомков
В иерархическом представлении группы объектов также как и свойства можно включать в группы свойств.
Описанный алгоритм во многом аналогичен алгоритму построения контейнеров свойств в дизайне по умолчанию (с той лишь разницей, что там нет / не используется иерархия групп объектов). Также как и в механизме построения контейнеров, одна и та же группа свойств может включаться в иерархию несколько раз для различных групп объектов
После того как иерархия построена, форма экспортируется / импортируется рекурсивно по следующим правилам:
JSON:
JSON результат ::=
{ JSON с свойствами, группами объектов / свойств без родителей }
JSON с свойствами, группами свойств / объектов ::=
JSON свойства 1 | JSON группы свойств 1 | JSON группы объектов 1
JSON свойства 2 | JSON группы свойств 2 | JSON группы объектов 2
...
JSON свойства M | JSON группы свойств M | JSON группы объектов M
JSON свойства ::=
"имя свойства на форме" : значение свойства
JSON группы свойств ::=
"имя группы свойств" : { JSON с дочерними свойствами, группами свойств / объектов }
JSON групп ы объектов ::=
"имя группы объектов" : [
{ JSON с дочерними свойствами, группами свойств / объектов 1 },
{ JSON с дочерними свойствами, группами свойств / объектов 2 },
...
{ JSON с дочерними свойствами, группами свойств / объектов N },
]
XML:
XML результат ::=
<имя формы> XML с свойствами, группами свойств / объектов без родителей </имя формы>
XML с свойствами, группами свойств / объектов ::=
XML свойства 1 | XML группы свойств 1 | XML группы объектов 1
XML свойства 2 | XML группы свойств 2 | XML группы объектов 2
...
XML свойства M | XML группы свойств M | XML группы объектов M
XML свойства ::=
<имя свойства на форме> значение свойства </имя свойства на форме>
XML группы свойств ::=
<имя группы свойств> XML с дочерними свойствами, группами свойств / объектов </имя группы свойств>
XML группы объектов ::=
<имя группы объектов> XML с дочерними свойствами, группами свойств / объектов 1 </имя группы объектов>
<имя группы объектов> XML с дочерними свойствами, группами свойств / объектов 2 </имя группы объектов>
...
<имя группы объектов> XML с дочерними свойствами, группами свойств / объектов N </имя группы объектов>
При экспорте / импорте в XML для свойства на форме можно задать специальную опцию ATTR
. Соответственно при экспорте / импорте такого свойства его значение будет храниться не в отдельном теге, а в атрибуте родительского тега:
<родительский тег ... имя свойства на форме = "значение свойства" ...>
При импорте из XML имя самого верхнего тега (в правиле) игнорируется (по спецификации XML он всегда должен быть один).
Свойства, значения которых равны NULL
, а также группы свойств, внутри которых в результате экспорта нет ни одного тега, не экспортируются (игнорируются).
Предопределенное значение value
При импорте JSON, если для группы объектов массив ( [ ]
) значений содержит не объект ( { }
), а конкретное значение (например число, строку), то это значение автоматически преобразовывается в объект { "value" : значение }
. Аналогичное преобразование выполняется при экспорте группы объектов в JSON - если объект содержит ровно один ключ value
(то есть имеет вид { "value" : значение }
), то вместо него в результирующий JSON подставляется значение для этого ключа value
. Кроме "обычных" групп объектов эти же преобразования выполняются и для корневой пустой группы объектов - то ес ть например JSON ["ab","vv"]
, обрабатывается как JSON { "value" : ["ab","vv"] }
.
При импорте / экспорте XML, если свойство имеет имя value
, то значение такого свойства будет храниться не в отдельном теге, а внутри (в тексте) родительского тега (то есть, как если бы родительский тег сам был представлением свойства). Такое поведение обычно используется, если родительский тег имеет внутри другие теги / атрибуты (спецификация XML это позволяет).
При импорте XML, если группа объектов имеет имя value
, то читаются все теги (с любым именем).
Пространства имен в XML
В отличие от остальных форматов, в XML поддерживается такое понятие как пространства имен тегов и атрибутов.
В lsFusion для того, чтобы, к примеру, экспортировать свойство в тег с заданным пространством имен, необходимо задать имя этого свойства в специальном синтаксисе:
[namespace[=uri]:]name
Например: h:table
или h=http://www.w3.org/TR/html4:table
. Имя пространства имен (namespace) при необходимости может быть пустым. Если для пространства имен uri не задан, он наследуется от пространства имен с тем же именем в верхних тегах. Если в верхних тегах пространств имен с таким именем нет, uri автоматически считается равным http://www.w3.org/<имя пространства имен>
.
Задать описанное выше имя свойства (например h:table
) в синтаксисе lsFusion невозможно (так как в имени не может быть двоеточия), поэтому для задания такого имени экспорта необходимо использовать описанную выше опцию EXTID
.
Если в теге необходимо объявить пространство имен, но при этом чтобы сам тег ему не принадлежал, в экспорт необходимо добавить свойство с пометкой ATTR
и именем xmlns:namespace
. При этом предполагается, что в значении такого свойства будет uri объявляемого пространства имен.
Аналогичным образом работа с пространствами имен идет при импорте свойств, а также при работе с группами объектов / группами свойств.
Плоское представление
Каждый файл для группы объектов в плоском представлении является таблицей, в которой:
- Рядами являются наборы объектов этой группы объектов.
- Колонками - свойства, группы отображения которых равны это й группе объектов.
В CSV формате (при отсутствии первой строки-заголовка) колонки именуются по аналогии с XLS (то есть A
- первая, B
- вторая и т.п.)
Если при импорте формы колонка с именем свойства формы не найдена, то для импорта выбирается колонка следующая за колонкой предыдущего свойства в списке свойств формы (колонка parent
при этом считается первой).
Язык
Использование всех вышеперечисленных возможностей, как и задание структуры формы, осуществляется при помощи инструкции FORM
.
Открытие формы
Для отображения формы в структурированном представлении используется соответствующий оператор открытия формы в структурированном представлении.
Примеры
FORM exportSku
OBJECTS st = Store
OBJECTS s = Sku
PROPERTIES(s) id, name, weight
FILTERS in(st, s)
;
exportSku (Store store) {
// выгружаем в DBF все Sku, для которых задано in (Store, Sku) для нужного склада
EXPORT exportSku OBJECTS st = store DBF CHARSET 'CP866';
EXPORT exportSku XML;
EXPORT exportSku OBJECTS st = store CSV ',';
}
date = DATA DATE (INTEGER);
sku = DATA BPSTRING[50] (INTEGER);
price = DATA NUMERIC[14,2] (INTEGER);
order = DATA INTEGER (INTEGER);
FORM import
OBJECTS o = INTEGER // заказы
OBJECTS od = INTEGER // строки заказов
PROPERTIES (o) dateOrder = date // импортируем дату из поля dateOrder
PROPERTIES (od) sku = sku, price = price // импортируем товар количество из полей sku и price
FILTERS order(od) = o // в order - записываем верхний заказ
;
importForm() {
INPUT f = FILE DO {
IMPORT import JSON FROM f;
SHOW import; // показываем что импортировалось
// создаем объекты в базе
FOR DATE date = date(INTEGER io) NEW o = Order DO {
date(o) <- date;
FOR order(INTEGER iod) = io NEW od = OrderDetail DO {
price(od) <- price(iod);
sku(od) <- GROUP MAX Sku sku IF name(sku) = sku(iod); // находим sku с данным именем
}
}
}
}