# Спецификация MXL DSL — JSON-формат описания табличного документа Компактный JSON-формат для описания макетов табличных документов 1С (SpreadsheetDocument). Используется навыками `/mxl-compile` (JSON → XML) и `/mxl-decompile` (XML → JSON). Оформление — шрифты, стили, цвета, рамки, колоночные раскладки — в `mxl-dsl-styles.md`; полный перечень свойств стиля — в `mxl-dsl-format-properties.md`. ## Пример ```json { "columns": 10, "defaultWidth": 30, "columnWidths": { "1": 15, "2-8": 40, "9-10": 50 }, "fonts": { "default": { "face": "Arial", "size": 10 }, "bold": { "face": "Arial", "size": 10, "bold": true }, "header": { "face": "Arial", "size": 14, "bold": true } }, "styles": { "default": {}, "header": { "font": "header", "horizontalAlignment": "Center" }, "label": { "font": "bold" }, "bordered": { "border": "Solid" }, "bordered-right": { "border": "Solid", "horizontalAlignment": "Right" }, "total-right": { "font": "bold", "topBorder": "Solid", "horizontalAlignment": "Right" } }, "areas": [ { "name": "Заголовок", "rows": [ { "height": 20, "cells": [ { "col": 1, "span": 10, "style": "header", "param": "ТекстЗаголовка" } ]} ] }, { "name": "ШапкаТаблицы", "rows": [ { "rowStyle": "bordered", "cells": [ { "col": 1, "text": "№" }, { "col": 2, "span": 6, "text": "Наименование" }, { "col": 9, "text": "Кол-во" }, { "col": 10, "text": "Сумма" } ]} ] }, { "name": "Строка", "rows": [ { "rowStyle": "bordered", "cells": [ { "col": 1, "param": "НомерСтроки" }, { "col": 2, "span": 6, "param": "Товар", "detail": "Номенклатура" }, { "col": 9, "style": "bordered-right", "param": "Количество" }, { "col": 10, "style": "bordered-right", "param": "Сумма" } ]} ] }, { "name": "Итого", "rows": [ { "cells": [ { "col": 8, "span": 2, "style": "total-right", "text": "Итого:" }, { "col": 10, "style": "total-right", "param": "Всего" } ]} ] } ] } ``` ## Верхний уровень | Поле | Обяз. | По умолч. | Описание | |------|:-----:|-----------|----------| | `columns` | да | — | Количество колонок в раскладке по умолчанию. `0` допустимо: значит, все строки живут в раскладках из `columnSets` | | `page` | нет | — | Формат страницы: `"A4-landscape"` (780), `"A4-portrait"` (540) или число. Автоматически вычисляет `defaultWidth` из суммы пропорций `"Nx"` | | `defaultWidth` | нет | 10 | Ширина колонок по умолчанию. Игнорируется если задан `page` и все колонки используют `"Nx"` | | `columnWidths` | нет | `{}` | Ширины колонок. Ключи 1-based: `"1"`, `"3-14"`, `"5,7,9"`. Значения: число (абсолют) или `"Nx"` (множитель от defaultWidth, напр. `"2x"`, `"0.5x"`) | | `columnStyles` | нет | — | Оформление колонок: те же ключи, значение — имя стиля (см. `mxl-dsl-styles.md`) | | `textLanguages` | нет | `["ru"]` | Языки, на которых пишется текст, заданный строкой (см. ниже) | | `fonts` | нет | — | Именованные шрифты (если не задано, создаётся Arial 10) | | `styles` | нет | `{}` | Именованные стили (см. `mxl-dsl-styles.md`) | | `areas` | да | — | Массив областей — диапазонов подряд идущих строк (порядок = порядок в документе); имя необязательно | | `namedAreas` | нет | — | Именованные области, заданные координатами (см. ниже) | | `columnSets` | нет | — | Дополнительные колоночные раскладки (см. `mxl-dsl-styles.md`) | | `rowGroups` | нет | — | Группы строк (см. ниже) | | `columnGroups` | нет | — | Группы колонок (см. ниже) | | `header` / `footer` | нет | — | Верхний и нижний колонтитулы (см. ниже) | | `printSettings` | нет | — | Параметры печати (см. ниже) | ## Области (`areas[]`) | Поле | Обяз. | Описание | |------|:-----:|----------| | `name` | нет | Имя области для `Макет.ПолучитьОбласть("Имя")` | | `columnSet` | нет | Ссылка на раскладку из `columnSets` | | `rows` | да | Массив строк | Макет собирается из областей — диапазонов подряд идущих строк. Имя делает область именованной: она доступна в коде как `Макет.ПолучитьОбласть("Имя")` и занимает строки своего диапазона. **Область без имени** — просто кусок сетки: так описываются строки, не принадлежащие ни одной именованной области. ## Именованные области координатами (`namedAreas[]`) Для областей, которые диапазоном подряд идущих строк не описываются: полоса колонок, прямоугольник, ячейка, а также пересекающиеся с другими. | Поле | Обяз. | Описание | |------|:-----:|----------| | `name` | да | Имя области | | `rows` | \* | Строки: число или диапазон `"N-M"`, 1-based | | `cols` | \* | Колонки: число или диапазон `"N-M"`, 1-based | \* Обязательна хотя бы одна из осей. **Тип области не указывается** — он следует из того, какие оси заданы, как в `ТабличныйДокумент.Область()`: только строки → полоса строк, только колонки → полоса колонок, обе оси → прямоугольник, одиночные значения по обеим осям → одна ячейка. ```json "namedAreas": [ { "name": "ОбластьПечатиПоВысоте", "rows": "1-48" }, { "name": "ОбластьПечатиПоШирине", "cols": "1-35" }, { "name": "HZY", "rows": 9, "cols": "16-17" } ] ``` Диапазон — та же грамматика, что у `columnWidths`, но **только** число или `"N-M"`: список через запятую запрещён, область непрерывна. Имя обязательно, и хотя бы одна ось должна быть задана; нарушение любого из этих правил → ненулевой код выхода и сообщение в stderr. ## Строки (`rows[]`) | Поле | По умолч. | Описание | |------|-----------|----------| | `height` | — | Высота строки (если не задана, используется авто) | | `hidden` | `false` | Скрыть строку | | `rowStyle` | — | Стиль строки: ложится и на саму строку, и на ВСЕ её колонки (заполняет пустоты рамками) | | `cells` | `[]` | Массив ячеек | | `empty` | — | Количество подряд идущих пустых строк (заменяет N отдельных `{}`) | Строка без `cells` и `rowStyle` → пустая строка. `{ "empty": 3 }` эквивалентно трём `{}`. `height` и `hidden` — собственные свойства строки: у ячейки таких нет, и в её оформление они не попадают. Всё остальное оформление строки задаётся через `rowStyle`. ### Короткая форма: строка массивом Вместо объекта строка может быть массивом ячеек — позиция определяется порядком, `col` не указывается. | Элемент | Значение | |---------|----------| | `"текст"` | Статический текст (`text`) | | `{ "ru": "…", "en": "…" }` | Тот же текст на нескольких языках | | `"{Имя}"` | Параметр (`param`) | | `">"` | Продолжение ячейки слева — увеличивает её `span` | | `"|"` | Продолжение ячейки сверху — увеличивает её `rowspan` | | `null` | Пустая колонка: позиция занята, ячейка не создаётся | | `{ ... }` | Обычная ячейка **без** `col`; нужна для `style`, `detail`, `template` | Объект-элемент трактуется по его ключам: если среди них есть ключ ячейки (`span`, `rowspan`, `style`, `param`, `detail`, `text`, `template`, `valueType`, `controlType`, `value`, `control`) — объект описывает свойства ячейки. Иначе он целиком считается её текстом, а его ключи — идентификаторами языков. ```json "rows": [ ["Вид", "Остаток", ">", "Итог"], ["|", "начало", "конец", "|"], ["{Вид}", "{Нач}", "{Кон}", "{Итог}"] ] ``` Здесь «Вид» и «Итог» объединены по вертикали на две строки, «Остаток» — по горизонтали на две колонки. Ограничения короткой формы: - не задать `height` и `rowStyle` — это свойства строки, а не ячейки; - не выразить текст, совпадающий с `">"`, `"|"` или с шаблоном `"{...}"`. Маркеру нужно, что продолжать: `">"` требует ячейку слева в той же строке, `"|"` — ячейку сверху. Объектный элемент не должен нести `col`: позиция уже задана порядком. Число элементов не может превышать `columns`. Нарушение любого из этих правил → ненулевой код выхода и сообщение в stderr. ## Ячейки (`cells[]`) | Поле | Обяз. | По умолч. | Описание | |------|:-----:|-----------|----------| | `col` | да | — | Позиция колонки (1-based). В короткой форме строки не указывается — позиция берётся из порядка | | `span` | нет | `1` | Объединение по горизонтали (количество колонок) | | `rowspan` | нет | `1` | Объединение по вертикали (количество строк) | | `style` | нет | rowStyle | Стиль ячейки (переопределяет rowStyle) | | `param` | нет | — | Параметр заполнения | | `detail` | нет | — | Параметр расшифровки. Самостоятельный ключ: ставится и на ячейку без `param` — с текстом, пустую или поле ввода | | `text` | нет | — | Статический текст. Строка или объект `{ ru, en }` — см. ниже | | `template` | нет | — | Шаблонный текст с `[Параметр]`. Строка или объект, как `text` | | `valueType` | нет | — | Тип значения: ячейка становится полем ввода (см. ниже) | | `controlType` | нет | `input` | Элемент управления поля ввода: `input` или `checkbox`. Только вместе с `valueType` | | `value` | нет | — | Значение в поле ввода. Только вместе с `valueType` | | `control` | нет | — | Настройки элемента управления в записи платформы (base64). Раундтрип, не для ручного авторинга | | `note` | нет | — | Примечание к ячейке (см. ниже) | ### Содержимое ячейки Задаётся ровно одним из ключей, объявлять способ заполнения отдельно не нужно: - `param` — параметр заполнения; - `template` — текст со вставками `[Параметр]`; - `text` — статический текст; - ничего — пустая ячейка (нужна, например, ради рамки). ### Текст на нескольких языках `text` и `template` принимают строку или объект «язык → текст». Объект даёт по надписи на каждый язык, в порядке ключей. Строка означает один и тот же текст на всех языках макета — по умолчанию только русский. ```json { "col": 1, "text": "Наименование" } { "col": 2, "text": { "ru": "Поставщик", "en": "Supplier" } } ``` Набор языков задаётся документным ключом `textLanguages`: ```json { "columns": 3, "textLanguages": ["ru", "en"], "areas": [] } ``` С таким объявлением `"Наименование"` из примера выше даст надпись и под `ru`, и под `en`. Ключ ни на что в конфигурации не смотрит — это просто список языков, на которые разворачивается строка. Пустая строка — это текст: ячейка с `"text": ""` даёт пустую надпись, а не ячейку без текста. ## Ячейка-поле ввода Ячейка может не показывать текст, а принимать значение от пользователя — так делают макеты для ввода данных. Достаточно задать тип значения: ```json { "col": 1, "valueType": "Number(15,3,nonneg)" } { "col": 2, "valueType": "String(10)" } { "col": 3, "valueType": "Boolean", "controlType": "checkbox" } { "col": 4, "valueType": "CatalogRef.Валюты" } { "col": 5, "valueType": "Boolean + String + Date + CatalogRef.Валюты" } { "col": 6, "valueType": "AnyRef" } ``` Грамматика типа: | Запись | Значение | |---|---| | `Boolean` | булево | | `String`, `String(10)`, `String(10,fixed)` | строка; без длины — неограниченная, `fixed` — фиксированной длины | | `Number`, `Number(15,3)`, `Number(15,3,nonneg)` | число; без параметров — без ограничения разрядности, `nonneg` — неотрицательное | | `Date`, `DateTime`, `Time` | дата, дата со временем, время | | `CatalogRef.Валюты`, `DocumentRef.Реализация`, `EnumRef.Статусы`, `DefinedType.Сумма` | ссылочный тип | | `CatalogRef`, `DocumentRef`, `AnyRef` | категория целиком: любая ссылка этого вида | | `A + B` | составной тип; повтор одного примитива недопустим | Русские имена принимаются наравне с английскими: `Число(15,3)`, `Строка(10)`, `СправочникСсылка.Валюты`. `text` и `template` в такой ячейке недопустимы — платформа не показывает текст там, где вводится значение. `param` и `detail` допустимы: они описывают заполнение и расшифровку, а не содержимое. Пустой тип `"valueType": ""` — «ячейка содержит значение», но тип не ограничен. Значение поля ввода задаётся ключом `value`, и его тип выражается литералом JSON: строка — строкой, число — числом, булево — `true`/`false`. Приведения к объявленному типу **не происходит**: платформа хранит значение с его собственным типом и совпадать с объявленным он не обязан (у ссылочного и составного типа значение всегда строковое). Пустая строка означает пустое значение объявленного типа. Дата записывается строкой в формате `ГГГГ-ММ-ДДTчч:мм:сс` и читается как дата только у ячейки, объявленной датой. ```json { "col": 1, "valueType": "Number(15,3)", "value": 12.5 } { "col": 2, "valueType": "String(10)", "value": "5" } { "col": 3, "valueType": "Boolean", "value": true } { "col": 4, "valueType": "DateTime", "value": "" } ``` `controlType` нужен редко: умолчание платформы — поле ввода, и оно применяется ко всем типам, включая `Boolean`. Флажок задаётся явно. Значение `"none"` (тега элемента управления нет вовсе) — форма раундтрипа, для ручного авторинга не нужна. ## Примечание к ячейке Всплывающая подсказка, которую платформа показывает при наведении. Задаётся ключом `note` — строкой, объектом «язык → текст» или полной формой: ```json { "col": 1, "text": "Итого", "note": "Сумма без НДС" } { "col": 2, "note": { "ru": "на дату документа", "en": "as of the document date" } } { "col": 3, "note": { "text": "не более 20%", "style": "жёлтая-подсказка" } } { "col": 4, "note": { "text": "…", "autoSize": false, "box": { "top": 58, "left": -175, "bottom": 362, "right": 478 } } } ``` Объект трактуется по ключам — так же, как текст ячейки в короткой форме строки: есть ключ примечания (`text`, `style`, `box`, `autoSize`, `anchor`) → это описание примечания, иначе ключи считаются идентификаторами языков. | Поле | По умолч. | Описание | |------|-----------|----------| | `text` | — | Текст подсказки: строка или объект «язык → текст» | | `style` | стиль подсказки | Имя стиля из `styles`; без него — оформление, которое даёт Конфигуратор | | `autoSize` | `true` | Подгонять ли размер окошка под текст | | `box` | канонический | Смещения окошка: `top`, `left` — положение, `bottom`, `right` — размер | | `anchor` | `{ row: 1, col: 1 }` | Якорь начала окошка. Раундтрип, не для ручного авторинга | Координаты ячейки в примечании не задаются — платформа привязывает конец окошка к самой ячейке, и компилятор проставляет это сам. `autoSize` и `box` независимы: при автоподгоне размера положение окошка всё равно хранится. ## Колонтитулы У верхнего и нижнего колонтитула по три слота — `left`, `center`, `right` — и общие настройки: ```json "header": { "font": "мелкий", "verticalAlignment": "Bottom", "startPage": 2, "left": "Слева\nвторая строка", "center": "Стр. [&НомерСтраницы] из [&СтраницВсего]", "right": { "ru": "Справа", "en": "Right" } }, "footer": { "show": false, "center": { "formatted": "Итог красным" } } ``` | Поле | По умолч. | Описание | |------|-----------|----------| | `left`, `center`, `right` | — | Текст слота: строка, объект «язык → текст» или `{ "formatted": … }` | | `font` | — | Имя шрифта из `fonts` — на весь колонтитул | | `verticalAlignment` | — | Положение текста по вертикали: `Top`, `Center`, `Bottom` | | `show` | `true` | Выводить ли колонтитул | | `startPage` | `1` | Страница, с которой колонтитул печатается | Текст может быть многострочным (`\n`) и содержать поля `[&НомерСтраницы]`, `[&СтраницВсего]`, `[&Дата]`, `[&Время]` — платформа подставляет их при печати. `{ "formatted": … }` — форматированная строка: разметка живёт прямо в тексте (`жирный`, ``, ``). ## Параметры печати Плоский объект; имя ключа совпадает с именем свойства в выгрузке: ```json "printSettings": { "pageOrientation": "Landscape", "topMargin": 500, "leftMargin": 500, "bottomMargin": 500, "rightMargin": 500, "headerSize": 1000, "footerSize": 1000, "fitToPage": true, "firstPageNumber": 7 } ``` Допустимые ключи: `pageOrientation`, `scale`, `collate`, `copies`, `perPage`, `topMargin`, `leftMargin`, `bottomMargin`, `rightMargin`, `headerSize`, `footerSize`, `fitToPage`, `blackAndWhite`, `printerName`, `paper`, `paperSource`, `pageWidth`, `pageHeight`, `duplexType`, `pagePlacementAlternation`, `firstPageNumber`. Незнакомый ключ — ошибка. Порядок в объекте не важен: компилятор пишет свойства в том порядке, что и платформа. ## Группы строк и колонок Диапазон строк или колонок, который сворачивается кнопкой на полях. Задаются плоским списком; вложенность выражена вхождением одного диапазона в другой: ```json "rowGroups": [ { "rows": "2-4" }, { "rows": 3 }, { "rows": 5, "name": "Итоговая", "collapsed": true, "titleLocation": "begin" } ], "columnGroups": [ { "cols": "2-3", "name": { "ru": "Показатели", "en": "Values" } }, { "cols": 3 } ] ``` | Поле | Обяз. | По умолч. | Описание | |------|:-----:|-----------|----------| | `rows` / `cols` | да | — | Диапазон 1-based: число или `"N-M"` | | `name` | нет | — | Имя группы: строка или объект «язык → текст» | | `collapsed` | нет | `false` | Свёрнута ли группа при открытии | | `titleLocation` | нет | `auto` | Расположение заголовка: `begin`, `end`, `auto` | Диапазоны либо вложены, либо не пересекаются — частичное пересечение платформа не хранит, и компилятор отвергает его с ненулевым кодом выхода. Число уровней вложенности считается само. Порядок в списке не важен: компилятор пишет группы так же, как платформа, — родитель раньше вложенных, по возрастанию начала. ## `rowStyle` — оформление строки Стиль применяется ко ВСЕЙ ширине строки: позиции без явных ячеек получают тот же стиль. Так в табличных строках получаются сплошные рамки. Он же становится оформлением самой строки — именно так платформа хранит строку, оформленную целиком. Стиль конкретной ячейки (`style`) перекрывает `rowStyle` для этой ячейки. Если в предыдущих строках той же области есть ячейки с `rowspan`, их колонки при автозаполнении пропускаются. ## Ограничения DSL описывает не все конструкции табличного документа. Перечисленное ниже **теряется при round-trip** (`/mxl-decompile` → `/mxl-compile`): в JSON оно не попадает, в сгенерированный XML не возвращается. - объединения, не привязанные к ячейке (по всей высоте или ширине документа); - рисунки и картинки, в том числе штрихкоды; - область печати. Пересборка макета из DSL — это полная перегенерация, а не точечная правка XML, поэтому diff после round-trip обычно шире фактической доработки. Отдельно про побайтовое совпадение. В макетах, которые долго правили в Конфигураторе, встречаются следы прежних состояний: формат ячейки может нести ширину колонки, которая с тех пор изменилась. Такие значения не описывают итоговый документ и из него не выводятся, поэтому собранный XML совпадёт с исходным не всегда — при полностью сохранённом содержании.