Именованная область ссылается на дополнительный набор колонок тегом columnsID, и эта ссылка терялась целиком: на пилоте кампании она давала 3572 расхождения из 3572 в своей категории, на корпусе таких областей 913 483 прямоугольных, 20 063 полосы строк и 743 полосы колонок. Ключ namedAreas[].columnSet имеет три состояния: ключа нет — привязка выводится из накрытых строк (совпадает у 1 021 570 областей корпуса из 1 044 339), "" — привязки нет вовсе, имя набора — явная привязка. Переопределение обязательно: у областей типа Rows 13 623 повторяют раскладку строк, а 8 179 её не несут при тех же строках. Декомпилятор пишет ключ, только когда он не выводится, а область, чья привязка расходится с раскладкой её строк, уводит из блочной формы в namedAreas — иначе блоком её не выразить. Пустая строка тоже попадает в карту «строка → раскладка»: без этого привязка области, накрывающей пустые строки, не выводилась. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
27 KiB
Спецификация MXL DSL — JSON-формат описания табличного документа
Компактный JSON-формат для описания макетов табличных документов 1С (SpreadsheetDocument). Используется навыками /mxl-compile (JSON → XML) и /mxl-decompile (XML → JSON).
Оформление — шрифты, стили, цвета, рамки, колоночные раскладки — в mxl-dsl-styles.md;
полный перечень свойств стиля — в mxl-dsl-format-properties.md.
Пример
{
"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 |
columnSet |
нет | Колоночная раскладка области. Без ключа выводится из накрытых строк, "" — привязки нет |
* Обязательна хотя бы одна из осей.
Тип области не указывается — он следует из того, какие оси заданы, как в ТабличныйДокумент.Область(): только строки → полоса строк, только колонки → полоса колонок, обе оси → прямоугольник, одиночные значения по обеим осям → одна ячейка.
"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 |
| `" | "` |
null |
Пустая колонка: позиция занята, ячейка не создаётся |
{ ... } |
Обычная ячейка без col; нужна для style, detail, template |
Объект-элемент трактуется по его ключам: если среди них есть ключ ячейки (span, rowspan,
style, param, detail, text, template, valueType, controlType, value,
control) — объект
описывает
свойства ячейки. Иначе он целиком считается её текстом, а его ключи — идентификаторами языков.
"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 принимают строку или объект «язык → текст». Объект даёт по надписи на каждый язык, в порядке ключей. Строка означает один и тот же текст на всех языках макета — по умолчанию только русский.
{ "col": 1, "text": "Наименование" }
{ "col": 2, "text": { "ru": "Поставщик", "en": "Supplier" } }
Набор языков задаётся документным ключом textLanguages:
{ "columns": 3, "textLanguages": ["ru", "en"], "areas": [] }
С таким объявлением "Наименование" из примера выше даст надпись и под ru, и под en.
Ключ ни на что в конфигурации не смотрит — это просто список языков, на которые разворачивается строка.
Пустая строка — это текст: ячейка с "text": "" даёт пустую надпись, а не ячейку без текста.
Ячейка-поле ввода
Ячейка может не показывать текст, а принимать значение от пользователя — так делают макеты для ввода данных. Достаточно задать тип значения:
{ "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чч:мм:сс
и читается как дата только у ячейки, объявленной датой.
{ "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 —
строкой, объектом «язык → текст» или полной формой:
{ "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 — и общие настройки:
"header": {
"font": "мелкий",
"verticalAlignment": "Bottom",
"startPage": 2,
"left": "Слева\nвторая строка",
"center": "Стр. [&НомерСтраницы] из [&СтраницВсего]",
"right": { "ru": "Справа", "en": "Right" }
},
"footer": {
"show": false,
"center": { "formatted": "<b>Итог</> <colorstyle -16>красным</>" }
}
| Поле | По умолч. | Описание |
|---|---|---|
left, center, right |
— | Текст слота: строка, объект «язык → текст» или { "formatted": … } |
font |
— | Имя шрифта из fonts — на весь колонтитул |
verticalAlignment |
— | Положение текста по вертикали: Top, Center, Bottom |
show |
true |
Выводить ли колонтитул |
startPage |
1 |
Страница, с которой колонтитул печатается |
Текст может быть многострочным (\n) и содержать поля [&НомерСтраницы], [&СтраницВсего],
[&Дата], [&Время] — платформа подставляет их при печати. { "formatted": … } — форматированная
строка: разметка живёт прямо в тексте (<b>жирный</>, <fontsize 12>, <colorstyle -16>).
Параметры печати
Плоский объект; имя ключа совпадает с именем свойства в выгрузке:
"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. Незнакомый ключ — ошибка. Порядок в объекте не
важен: компилятор пишет свойства в том порядке, что и платформа.
Группы строк и колонок
Диапазон строк или колонок, который сворачивается кнопкой на полях. Задаются плоским списком; вложенность выражена вхождением одного диапазона в другой:
"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 совпадёт с исходным не всегда — при полностью сохранённом содержании.