# Спецификация MXL DSL — JSON-формат описания табличного документа Компактный JSON-формат для описания макетов табличных документов 1С (SpreadsheetDocument). Используется навыками `/mxl-compile` (JSON → XML) и `/mxl-decompile` (XML → JSON). ## Пример ```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", "align": "center" }, "label": { "font": "bold" }, "bordered": { "border": "all" }, "bordered-right": { "border": "all", "align": "right" }, "total-right": { "font": "bold", "border": "top", "align": "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"`) | | `fonts` | нет | — | Именованные шрифты (если не задано, создаётся Arial 10) | | `styles` | нет | `{}` | Именованные стили | | `areas` | да | — | Массив областей — диапазонов подряд идущих строк (порядок = порядок в документе); имя необязательно | | `namedAreas` | нет | — | Именованные области, заданные координатами (см. ниже) | | `columnSets` | нет | — | Дополнительные колоночные раскладки: своя ширина колонок у группы строк (см. ниже) | ## Шрифты (`fonts.`) | Поле | По умолч. | Описание | |------|-----------|----------| | `face` | `"Arial"` | Имя шрифта | | `size` | `10` | Размер | | `bold` | `false` | Жирный | | `italic` | `false` | Курсив | | `underline` | `false` | Подчёркнутый | | `strikeout` | `false` | Зачёркнутый | Шрифт `"default"` используется когда стиль не указывает шрифт явно. Если не определён, создаётся автоматически (Arial 10). ## Стили (`styles.`) | Поле | По умолч. | Описание | |------|-----------|----------| | `font` | `"default"` | Ссылка на имя шрифта | | `align` | — | `left`, `center`, `right` | | `valign` | — | `top`, `center` | | `border` | — | Стороны рамки: `all`, `top`, `bottom`, `left`, `right`, `none`. Через запятую: `"top,bottom"` | | `borderWidth` | `"thin"` | Толщина рамки: `thin` (1px) или `thick` (2px) | | `wrap` | `false` | Перенос текста | | `format` | — | Формат данных 1С: `"ЧЦ=15; ЧДЦ=2"`, `"ДФ=dd.MM.yyyy"` и т.д. | ## Области (`areas[]`) | Поле | Обяз. | Описание | |------|:-----:|----------| | `name` | нет | Имя области для `Макет.ПолучитьОбласть("Имя")` | | `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. ## Колоночные раскладки (`columnSets`) Группа строк может иметь собственные ширины колонок — в 1С это «индивидуальная ширина колонок». Документные `columns` и `columnWidths` описывают раскладку по умолчанию; дополнительные объявляются в `columnSets`, а область ссылается на нужную ключом `columnSet` — так же, как ячейка ссылается на `styles` через `style`. ```json { "columns": 52, "columnWidths": { "1": 8 }, "columnSets": { "таблица": { "columns": 52, "columnWidths": { "1": 7, "2-52": 24 } } }, "areas": [ { "name": "Шапка", "rows": [ ... ] }, { "name": "ТабличнаяЧасть", "columnSet": "таблица", "rows": [ ... ] } ] } ``` Раскладка описывается той же парой полей, что и документная: `columns` — количество колонок (у раскладок оно обычно разное), `columnWidths` — ширины. Ключ словаря — имя раскладки; в макетах, полученных через `/mxl-decompile`, это идентификатор из исходного файла, при описании с нуля — любая строка. Все строки области получают раскладку области, поэтому одна область не может смешивать раскладки. Позиции колонок (`col`, `span`) проверяются по ширине раскладки СВОЕЙ области, а не документной. Ссылка на необъявленную раскладку → ненулевой код выхода и сообщение в stderr. ## Строки (`rows[]`) | Поле | По умолч. | Описание | |------|-----------|----------| | `height` | — | Высота строки (если не задана, используется авто) | | `rowStyle` | — | Стиль для ВСЕХ колонок (заполняет пустоты рамками) | | `cells` | `[]` | Массив ячеек | | `empty` | — | Количество подряд идущих пустых строк (заменяет N отдельных `{}`) | Строка без `cells` и `rowStyle` → пустая строка. `{ "empty": 3 }` эквивалентно трём `{}`. ### Короткая форма: строка массивом Вместо объекта строка может быть массивом ячеек — позиция определяется порядком, `col` не указывается. | Элемент | Значение | |---------|----------| | `"текст"` | Статический текст (`text`) | | `"{Имя}"` | Параметр (`param`) | | `">"` | Продолжение ячейки слева — увеличивает её `span` | | `"|"` | Продолжение ячейки сверху — увеличивает её `rowspan` | | `null` | Пустая колонка: позиция занята, ячейка не создаётся | | `{ ... }` | Обычная ячейка **без** `col`; нужна для `style`, `detail`, `template` | ```json "rows": [ ["Вид", "Остаток", ">", "Итог"], ["|", "начало", "конец", "|"], ["{Вид}", "{Нач}", "{Кон}", "{Итог}"] ] ``` Здесь «Вид» и «Итог» объединены по вертикали на две строки, «Остаток» — по горизонтали на две колонки. Ограничения короткой формы: - не задать `height` и `rowStyle` — это свойства строки, а не ячейки; - не выразить текст, совпадающий с `">"`, `"|"` или с шаблоном `"{...}"`. Маркеру нужно, что продолжать: `">"` требует ячейку слева в той же строке, `"|"` — ячейку сверху. Объектный элемент не должен нести `col`: позиция уже задана порядком. Число элементов не может превышать `columns`. Нарушение любого из этих правил → ненулевой код выхода и сообщение в stderr. ## Ячейки (`cells[]`) | Поле | Обяз. | По умолч. | Описание | |------|:-----:|-----------|----------| | `col` | да | — | Позиция колонки (1-based). В короткой форме строки не указывается — позиция берётся из порядка | | `span` | нет | `1` | Объединение по горизонтали (количество колонок) | | `rowspan` | нет | `1` | Объединение по вертикали (количество строк) | | `style` | нет | rowStyle | Стиль ячейки (переопределяет rowStyle) | | `param` | нет | — | Параметр заполнения | | `detail` | нет | — | Параметр расшифровки (только с `param`) | | `text` | нет | — | Статический текст | | `template` | нет | — | Шаблонный текст с `[Параметр]` | ### Содержимое ячейки Задаётся ровно одним из ключей, объявлять способ заполнения отдельно не нужно: - `param` — параметр заполнения; - `template` — текст со вставками `[Параметр]`; - `text` — статический текст; - ничего — пустая ячейка (нужна, например, ради рамки). ## `rowStyle` — автозаполнение Стиль применяется ко ВСЕЙ ширине строки: позиции без явных ячеек получают тот же стиль. Так в табличных строках получаются сплошные рамки. Если в предыдущих строках той же области есть ячейки с `rowspan`, их колонки при автозаполнении пропускаются. ## Ограничения DSL описывает не все конструкции табличного документа. Перечисленное ниже **теряется при round-trip** (`/mxl-decompile` → `/mxl-compile`): в JSON оно не попадает, в сгенерированный XML не возвращается. - ячейки-поля ввода (`containsValue` / `valueType` / `controlType`); - объединения, не привязанные к ячейке (по всей высоте или ширине документа); - рисунки и картинки, в том числе штрихкоды; - цвет текста, цвет фона ячейки, скрытые строки и колонки, отступ; - рамка с разным стилем у разных сторон; стили линий кроме сплошной; - группировки строк и колонок; - колонтитулы, параметры печати, область печати; - многоязычные надписи: при разборе берётся первый вариант текста, при генерации язык всегда `ru`, остальные теряются. Пересборка макета из DSL — это полная перегенерация, а не точечная правка XML, поэтому diff после round-trip обычно шире фактической доработки.