feat(mxl-compile,mxl-decompile): значение ячейки-поля ввода и настройки элемента управления

Ключ ячейки value несёт значение, набранное в поле ввода, ключ control —
сериализованные настройки самого элемента управления. Оба живут у ячейки,
а не в палитре формата: у двух ячеек с одинаковым оформлением значения
разные.

Тип значения выражается литералом JSON и приведения к объявленному типу
НЕ делается. Так пишет платформа: ссылочный и составной тип она хранит
строкой, а при смене типа ячейки прежнее значение не переписывает — на
корпусе 560 ячеек объявлены числом, но несут строку. Приведение здесь
означало бы переписывать данные при пересборке. Дата литералом JSON не
выражается, поэтому едет строкой и читается как дата только у ячейки,
объявленной датой.

Настройки элемента управления возим дословно: 26 370 вхождений корпуса
дают всего 163 различных блоба, разбирать структуру незачем. Переводы
строк внутри блоба приводим к LF на чтении — XML-парсеры двух портов
нормализуют их по-разному, и без этого порты давали разный JSON на одном
файле.

Стенд СЗначениями снова собирается байт в байт обоими портами: фикстура
обновлена до версии со значениями, флажком и блобом настроек.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-08-15 13:32:40 +03:00
co-authored by Claude Opus 5
parent 66bb285636
commit 43d2f660da
14 changed files with 951 additions and 17 deletions
+2 -2
View File
@@ -59,7 +59,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/mxl-compile.ps1" -J
styles: { name: { font, horizontalAlignment, verticalAlignment, textPlacement, styles: { name: { font, horizontalAlignment, verticalAlignment, textPlacement,
backColor, textColor, border, borderColor, format, hidden } }, backColor, textColor, border, borderColor, format, hidden } },
areas: [{ name, columnSet, rows: [{ height, hidden, rowStyle, cells: [ areas: [{ name, columnSet, rows: [{ height, hidden, rowStyle, cells: [
{ col, span, rowspan, style, param, detail, text, template, valueType, controlType } { col, span, rowspan, style, param, detail, text, template, valueType, controlType, value }
]}]}], ]}]}],
namedAreas: [{ name, rows, cols }], namedAreas: [{ name, rows, cols }],
columnSets: { name: { columns, columnWidths, columnStyles } } columnSets: { name: { columns, columnWidths, columnStyles } }
@@ -80,7 +80,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/mxl-compile.ps1" -J
- `col` — 1-based позиция колонки - `col` — 1-based позиция колонки
- `rowspan` — объединение строк вниз (rowStyle учитывает занятые ячейки) - `rowspan` — объединение строк вниз (rowStyle учитывает занятые ячейки)
- Содержимое ячейки задаётся одним из ключей: `param` — параметр заполнения, `text` — статический текст, `template` — текст со вставками `[Параметр]` - Содержимое ячейки задаётся одним из ключей: `param` — параметр заполнения, `text` — статический текст, `template` — текст со вставками `[Параметр]`
- `valueType` делает ячейку полем ввода (`"Number(15,3,nonneg)"`, `"String(10)"`, `"CatalogRef.Валюты"`, составной через ` + `); текста в такой ячейке быть не может, а `controlType: "checkbox"` меняет поле ввода на флажок - `valueType` делает ячейку полем ввода (`"Number(15,3,nonneg)"`, `"String(10)"`, `"CatalogRef.Валюты"`, составной через ` + `); текста в такой ячейке быть не может, а `controlType: "checkbox"` меняет поле ввода на флажок; `value` — значение в поле
Двухуровневая шапка массивами: Двухуровневая шапка массивами:
```json ```json
@@ -152,7 +152,8 @@
| `{ ... }` | Обычная ячейка **без** `col`; нужна для `style`, `detail`, `template` | | `{ ... }` | Обычная ячейка **без** `col`; нужна для `style`, `detail`, `template` |
Объект-элемент трактуется по его ключам: если среди них есть ключ ячейки (`span`, `rowspan`, Объект-элемент трактуется по его ключам: если среди них есть ключ ячейки (`span`, `rowspan`,
`style`, `param`, `detail`, `text`, `template`, `valueType`, `controlType`) — объект описывает `style`, `param`, `detail`, `text`, `template`, `valueType`, `controlType`, `value`) — объект
описывает
свойства ячейки. Иначе он целиком считается её текстом, а его ключи — идентификаторами языков. свойства ячейки. Иначе он целиком считается её текстом, а его ключи — идентификаторами языков.
```json ```json
@@ -184,6 +185,7 @@
| `template` | нет | — | Шаблонный текст с `[Параметр]`. Строка или объект, как `text` | | `template` | нет | — | Шаблонный текст с `[Параметр]`. Строка или объект, как `text` |
| `valueType` | нет | — | Тип значения: ячейка становится полем ввода (см. ниже) | | `valueType` | нет | — | Тип значения: ячейка становится полем ввода (см. ниже) |
| `controlType` | нет | `input` | Элемент управления поля ввода: `input` или `checkbox`. Только вместе с `valueType` | | `controlType` | нет | `input` | Элемент управления поля ввода: `input` или `checkbox`. Только вместе с `valueType` |
| `value` | нет | — | Значение в поле ввода. Только вместе с `valueType` |
### Содержимое ячейки ### Содержимое ячейки
@@ -248,6 +250,20 @@
Пустой тип `"valueType": ""` — «ячейка содержит значение», но тип не ограничен. Пустой тип `"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` нужен редко: умолчание платформы — поле ввода, и оно применяется ко всем типам, `controlType` нужен редко: умолчание платформы — поле ввода, и оно применяется ко всем типам,
включая `Boolean`. Флажок задаётся явно. Значение `"none"` (тега элемента управления нет вовсе) — включая `Boolean`. Флажок задаётся явно. Значение `"none"` (тега элемента управления нет вовсе) —
форма раундтрипа, для ручного авторинга не нужна. форма раундтрипа, для ручного авторинга не нужна.
@@ -266,8 +282,6 @@ DSL описывает не все конструкции табличного
round-trip** (`/mxl-decompile``/mxl-compile`): в JSON оно не попадает, в сгенерированный round-trip** (`/mxl-decompile``/mxl-compile`): в JSON оно не попадает, в сгенерированный
XML не возвращается. XML не возвращается.
- начальное значение ячейки-поля ввода и сериализованные настройки её элемента управления
(тип значения при этом переживает цикл);
- объединения, не привязанные к ячейке (по всей высоте или ширине документа); - объединения, не привязанные к ячейке (по всей высоте или ширине документа);
- рисунки и картинки, в том числе штрихкоды, и примечания к ячейкам; - рисунки и картинки, в том числе штрихкоды, и примечания к ячейкам;
- группировки строк и колонок; - группировки строк и колонок;
@@ -1,4 +1,4 @@
# mxl-compile v1.41 — Compile 1C spreadsheet from JSON # mxl-compile v1.42 — Compile 1C spreadsheet from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param( param(
[Parameter(Mandatory)] [Parameter(Mandatory)]
@@ -854,6 +854,14 @@ function Get-CellValueProps {
[Console]::Error.WriteLine("Cell 'controlType' requires 'valueType' ($where)") [Console]::Error.WriteLine("Cell 'controlType' requires 'valueType' ($where)")
exit 1 exit 1
} }
if ($null -ne $cell.PSObject.Properties['value'] -and $null -ne $cell.value) {
[Console]::Error.WriteLine("Cell 'value' requires 'valueType' ($where)")
exit 1
}
if ($null -ne $cell.control -and "$($cell.control)" -ne '') {
[Console]::Error.WriteLine("Cell 'control' requires 'valueType' ($where)")
exit 1
}
return $props return $props
} }
# Ячейка, содержащая значение, текста не несёт: платформа этого не допускает, и в корпусе # Ячейка, содержащая значение, текста не несёт: платформа этого не допускает, и в корпусе
@@ -885,6 +893,46 @@ function Get-CellValueProps {
return $props return $props
} }
# Значение ячейки-поля ввода — тег САМОЙ ячейки (<v>), а не запись палитры: у двух ячеек
# с одинаковым оформлением значения разные, и в дедупликацию формата оно не входит.
# Тип значения берём из литерала JSON и приведения НЕ делаем: платформа хранит значение с его
# собственным типом, и совпадать с объявленным он не обязан (ссылочный и составной тип она
# держит строкой, а при смене типа ячейки прежнее значение не переписывает).
function Get-CellValue {
param($cell, [string]$canonType, [string]$where)
$prop = $cell.PSObject.Properties['value']
if ($null -eq $prop -or $null -eq $prop.Value) { return $null }
$v = $prop.Value
if ($v -is [bool]) {
return @{ Type = 'xs:boolean'; Text = $(if ($v) { 'true' } else { 'false' }) }
}
if ($v -is [int] -or $v -is [long] -or $v -is [double] -or $v -is [decimal]) {
return @{ Type = 'xs:decimal'; Text = (Format-Num $v) }
}
$s = "$v"
if ($s -ne '') {
# Дата литералом JSON не выражается, поэтому едет строкой. Читаем её как дату только
# у ячейки, объявленной датой: там платформа других значений не держит.
if (($canonType -ceq 'Date' -or $canonType -ceq 'DateTime' -or $canonType -ceq 'Time') -and
$s -match '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$') {
return @{ Type = 'xs:dateTime'; Text = $s }
}
return @{ Type = 'xs:string'; Text = $s }
}
# Пустая строка — пустое значение ОБЪЯВЛЕННОГО типа: платформа так и пишет, когда текст
# ячейки к типу не привёлся. Ссылочный и составной тип пустого значения своего вида не
# имеют — там остаётся пустая строка.
if ($canonType -ceq 'Boolean') { return @{ Type = 'xs:boolean'; Text = 'false' } }
if ($canonType -like 'Number(*') { return @{ Type = 'xs:decimal'; Text = '0' } }
if ($canonType -ceq 'Date' -or $canonType -ceq 'DateTime' -or $canonType -ceq 'Time') {
return @{ Type = 'xs:dateTime'; Text = '0001-01-01T00:00:00' }
}
return @{ Type = 'xs:string'; Text = '' }
}
# --- 6. Format palette builder --- # --- 6. Format palette builder ---
$formatRegistry = [ordered]@{} # key -> hashtable with properties $formatRegistry = [ordered]@{} # key -> hashtable with properties
@@ -1140,7 +1188,7 @@ function Set-CellProp {
function Test-CellObject { function Test-CellObject {
param($el) param($el)
$cellKeys = @('col', 'span', 'rowspan', 'style', 'param', 'detail', 'text', 'template', $cellKeys = @('col', 'span', 'rowspan', 'style', 'param', 'detail', 'text', 'template',
'valueType', 'controlType') 'valueType', 'controlType', 'value', 'control')
foreach ($p in $el.PSObject.Properties) { foreach ($p in $el.PSObject.Properties) {
if ($cellKeys -contains $p.Name) { return $true } if ($cellKeys -contains $p.Name) { return $true }
} }
@@ -1613,6 +1661,8 @@ foreach ($area in $def.areas) {
Detail = $cell.detail Detail = $cell.detail
Text = $cell.text Text = $cell.text
Template = $cell.template Template = $cell.template
Value = $(if ($vp.Count -gt 0) { Get-CellValue $cell "$($vp['valueType'])" "area `"$areaName`", row $($localRow + 1)" } else { $null })
Control = $(if ($vp.Count -gt 0) { $cell.control } else { $null })
} }
$rowCells += $cellInfo $rowCells += $cellInfo
@@ -1719,6 +1769,22 @@ foreach ($area in $def.areas) {
if ($null -ne $cellInfo.Template) { Emit-CellText $cellInfo.Template } if ($null -ne $cellInfo.Template) { Emit-CellText $cellInfo.Template }
if ($null -ne $cellInfo.Value) {
X "`t`t`t`t`t<v xsi:type=`"$($cellInfo.Value.Type)`">$(Esc-XmlText $cellInfo.Value.Text)</v>"
}
# Настройки элемента управления платформа сериализует в base64 и держит у самой
# ячейки. Структуру не разбираем — возим дословно, иначе она теряется.
if ($null -ne $cellInfo.Control -and "$($cellInfo.Control)" -ne '') {
# Блоб платформа переносит по строкам, а X дописывает перевод строки сам —
# поэтому каждую строку блоба пишем отдельным вызовом, иначе перевод строки
# внутри значения разошёлся бы с остальным файлом.
$parts = @("$($cellInfo.Control)" -split "`r?`n")
$parts[0] = "`t`t`t`t`t<control xsi:type=`"xs:base64Binary`">$($parts[0])"
$parts[-1] = "$($parts[-1])</control>"
foreach ($p in $parts) { X $p }
}
# Расшифровка от параметра заполнения не зависит: на корпусе 20 404 ячейки несут # Расшифровка от параметра заполнения не зависит: на корпусе 20 404 ячейки несут
# её БЕЗ параметра (у текста, у пустой ячейки, у поля ввода) против 8 582 с ним. # её БЕЗ параметра (у текста, у пустой ячейки, у поля ввода) против 8 582 с ним.
# Пока она стояла внутри ветки параметра, две трети расшифровок терялись молча. # Пока она стояла внутри ветки параметра, две трети расшифровок терялись молча.
@@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# mxl-compile v1.41 — Compile 1C spreadsheet from JSON # mxl-compile v1.42 — Compile 1C spreadsheet from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse import argparse
import hashlib import hashlib
@@ -644,6 +644,45 @@ def emit_value_type_content(lines, indent, canon_type):
lines.extend(quals[q]) lines.extend(quals[q])
def cell_value(cell, canon_type, where):
"""Значение ячейки-поля ввода — тег САМОЙ ячейки (<v>), а не запись палитры: у двух ячеек
с одинаковым оформлением значения разные, и в дедупликацию формата оно не входит.
Тип значения берём из литерала JSON и приведения НЕ делаем: платформа хранит значение с его
собственным типом, и совпадать с объявленным он не обязан (ссылочный и составной тип она
держит строкой, а при смене типа ячейки прежнее значение не переписывает)."""
if 'value' not in cell:
return None
v = cell.get('value')
if v is None:
return None
if isinstance(v, bool):
return {'Type': 'xs:boolean', 'Text': 'true' if v else 'false'}
if isinstance(v, (int, float)):
# 8.0 обязано дать "8", как в PS-порту: там Convert.ToString инвариантной культурой
# хвостовой .0 не пишет, а str() в py — пишет.
text = str(int(v)) if (isinstance(v, float) and v.is_integer()) else str(v)
return {'Type': 'xs:decimal', 'Text': text}
s = str(v)
if s != '':
# Дата литералом JSON не выражается, поэтому едет строкой. Читаем её как дату только
# у ячейки, объявленной датой: там платформа других значений не держит.
if canon_type in ('Date', 'DateTime', 'Time') and re.match(r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$', s):
return {'Type': 'xs:dateTime', 'Text': s}
return {'Type': 'xs:string', 'Text': s}
# Пустая строка — пустое значение ОБЪЯВЛЕННОГО типа: платформа так и пишет, когда текст
# ячейки к типу не привёлся. Ссылочный и составной тип пустого значения своего вида не
# имеют — там остаётся пустая строка.
if canon_type == 'Boolean':
return {'Type': 'xs:boolean', 'Text': 'false'}
if canon_type.startswith('Number('):
return {'Type': 'xs:decimal', 'Text': '0'}
if canon_type in ('Date', 'DateTime', 'Time'):
return {'Type': 'xs:dateTime', 'Text': '0001-01-01T00:00:00'}
return {'Type': 'xs:string', 'Text': ''}
def cell_value_props(cell, where): def cell_value_props(cell, where):
"""Свойства значения ячейки — пустой набор, если ячейка обычная. Считаются ОДНОЙ функцией: """Свойства значения ячейки — пустой набор, если ячейка обычная. Считаются ОДНОЙ функцией:
пре-проход регистрации палитры и генерация обязаны получить один и тот же набор, иначе пре-проход регистрации палитры и генерация обязаны получить один и тот же набор, иначе
@@ -655,6 +694,12 @@ def cell_value_props(cell, where):
if ctl is not None and str(ctl) != '': if ctl is not None and str(ctl) != '':
print(f"Cell 'controlType' requires 'valueType' ({where})", file=sys.stderr) print(f"Cell 'controlType' requires 'valueType' ({where})", file=sys.stderr)
sys.exit(1) sys.exit(1)
if cell.get('value') is not None:
print(f"Cell 'value' requires 'valueType' ({where})", file=sys.stderr)
sys.exit(1)
if cell.get('control'):
print(f"Cell 'control' requires 'valueType' ({where})", file=sys.stderr)
sys.exit(1)
return props return props
# Ячейка, содержащая значение, текста не несёт: платформа этого не допускает, и в корпусе # Ячейка, содержащая значение, текста не несёт: платформа этого не допускает, и в корпусе
# нет ни одной такой ячейки из 370 197. # нет ни одной такой ячейки из 370 197.
@@ -1154,7 +1199,7 @@ def main():
ключей есть ключ схемы ячейки, во втором ключи — идентификаторы языков. Пересечений ключей есть ключ схемы ячейки, во втором ключи — идентификаторы языков. Пересечений
нет: в корпусе это ru, en, ru1, Русский.""" нет: в корпусе это ru, en, ru1, Русский."""
cell_keys = ('col', 'span', 'rowspan', 'style', 'param', 'detail', 'text', 'template', cell_keys = ('col', 'span', 'rowspan', 'style', 'param', 'detail', 'text', 'template',
'valueType', 'controlType') 'valueType', 'controlType', 'value', 'control')
return any(k in el for k in cell_keys) return any(k in el for k in cell_keys)
def expand_shorthand_row(row, area_name, row_idx, open_by_col, max_cols): def expand_shorthand_row(row, area_name, row_idx, open_by_col, max_cols):
@@ -1570,6 +1615,9 @@ def main():
'Detail': cell.get('detail'), 'Detail': cell.get('detail'),
'Text': cell.get('text'), 'Text': cell.get('text'),
'Template': cell.get('template'), 'Template': cell.get('template'),
'Value': (cell_value(cell, vp.get('valueType', ''),
f'area "{area_name}", row {local_row + 1}') if vp else None),
'Control': (cell.get('control') if vp else None),
} }
row_cells.append(cell_info) row_cells.append(cell_info)
@@ -1667,6 +1715,21 @@ def main():
if cell_info['Template'] is not None: if cell_info['Template'] is not None:
emit_cell_text(lines, cell_info['Template']) emit_cell_text(lines, cell_info['Template'])
if cell_info.get('Value') is not None:
val = cell_info['Value']
lines.append(f'\t\t\t\t\t<v xsi:type="{val["Type"]}">{esc_xml_text(val["Text"])}</v>')
# Настройки элемента управления платформа сериализует в base64 и держит у самой
# ячейки. Структуру не разбираем — возим дословно, иначе она теряется.
if cell_info.get('Control'):
# Блоб платформа переносит по строкам, а строки документа склеиваются
# позже — поэтому каждую строку блоба кладём отдельным элементом списка,
# иначе перевод строки внутри значения разошёлся бы с остальным файлом.
parts = str(cell_info['Control']).replace('\r\n', '\n').split('\n')
parts[0] = f'\t\t\t\t\t<control xsi:type="xs:base64Binary">{parts[0]}'
parts[-1] = f'{parts[-1]}</control>'
lines.extend(parts)
# Расшифровка от параметра заполнения не зависит: на корпусе 20 404 ячейки несут # Расшифровка от параметра заполнения не зависит: на корпусе 20 404 ячейки несут
# её БЕЗ параметра (у текста, у пустой ячейки, у поля ввода) против 8 582 с ним. # её БЕЗ параметра (у текста, у пустой ячейки, у поля ввода) против 8 582 с ним.
# Пока она стояла внутри ветки параметра, две трети расшифровок терялись молча. # Пока она стояла внутри ветки параметра, две трети расшифровок терялись молча.
@@ -1,4 +1,4 @@
# mxl-decompile v1.21 — Decompile 1C spreadsheet to JSON # mxl-decompile v1.22 — Decompile 1C spreadsheet to JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param( param(
[Parameter(Mandatory)] [Parameter(Mandatory)]
@@ -92,6 +92,25 @@ $valueControlNames = @{
# значение» без указания типа — самостоятельное состояние. # значение» без указания типа — самостоятельное состояние.
# Префикс ссылочного типа разрешаем по URI, а не по имени: локальное объявление платформа # Префикс ссылочного типа разрешаем по URI, а не по имени: локальное объявление платформа
# называет сгенерированным dNpM. Чужое пространство имён оставляем как есть. # называет сгенерированным dNpM. Чужое пространство имён оставляем как есть.
# Значение ячейки-поля ввода → литерал DSL. Тип значения выражается самим литералом:
# число → числом, булево → true/false, строка и дата → строкой. Пустое значение пишем
# как есть (0, false, пустая дата), а не схлопываем: так оно собирается обратно тем же
# типом независимо от того, какой тип объявлен у ячейки.
function ConvertTo-DslValue {
param([string]$xsiType, [string]$text)
if ($null -eq $text) { $text = '' }
if ($xsiType -ceq 'xs:boolean') { return ($text.Trim() -ceq 'true') }
if ($xsiType -ceq 'xs:decimal') {
$s = $text.Trim()
$i = 0; $d = 0.0
if ($s -notlike '*.*' -and [int]::TryParse($s, [ref]$i)) { return $i }
if ([double]::TryParse($s, [System.Globalization.NumberStyles]::Float,
[System.Globalization.CultureInfo]::InvariantCulture, [ref]$d)) { return $d }
return $s
}
return $text
}
function Get-ValueQualifier { function Get-ValueQualifier {
param($quals, [string]$kind, [string]$name, [string]$default = '') param($quals, [string]$kind, [string]$name, [string]$default = '')
if (-not $quals.ContainsKey($kind)) { return $default } if (-not $quals.ContainsKey($kind)) { return $default }
@@ -390,6 +409,22 @@ foreach ($riNode in $root.SelectNodes("d:rowsItem", $ns)) {
$dNode = $cContent.SelectSingleNode("d:detailParameter", $ns) $dNode = $cContent.SelectSingleNode("d:detailParameter", $ns)
if ($dNode) { $detail = $dNode.InnerText } if ($dNode) { $detail = $dNode.InnerText }
# Значение ячейки-поля ввода. Тип значения свой, из объявленного не выводится,
# поэтому читаем и его.
$value = $null
$vNode = $cContent.SelectSingleNode("d:v", $ns)
if ($vNode) {
$value = @{ Type = $vNode.GetAttribute("type", "http://www.w3.org/2001/XMLSchema-instance"); Text = $vNode.InnerText }
}
# Настройки элемента управления — сериализованный base64 у самой ячейки.
# Структуру не разбираем, возим дословно.
$control = $null
$ctlNode = $cContent.SelectSingleNode("d:control", $ns)
# Переводы строк внутри блоба приводим к LF: XML-парсеры нормализуют их
# по-разному, и без этого порты давали разный JSON на одном файле.
if ($ctlNode -and $ctlNode.InnerText) { $control = $ctlNode.InnerText -replace "`r`n", "`n" }
# Текст ячейки платформа хранит по элементу на язык. Раньше брался ПЕРВЫЙ, и всё # Текст ячейки платформа хранит по элементу на язык. Раньше брался ПЕРВЫЙ, и всё
# остальное терялось — в корпусе ERP 98% макетов держат текст и под ru, и под en. # остальное терялось — в корпусе ERP 98% макетов держат текст и под ru, и под en.
# Здесь собираем «язык → текст» как есть; свернётся в строку позже, когда станет # Здесь собираем «язык → текст» как есть; свернётся в строку позже, когда станет
@@ -423,6 +458,8 @@ foreach ($riNode in $root.SelectNodes("d:rowsItem", $ns)) {
FormatIdx = $cellFmtIdx FormatIdx = $cellFmtIdx
Param = $param Param = $param
Detail = $detail Detail = $detail
Value = $value
Control = $control
Text = $text Text = $text
HasText = $hasText HasText = $hasText
} }
@@ -1135,6 +1172,10 @@ foreach ($area in $blocks) {
# форматах корпуса. # форматах корпуса.
if ($name -cne 'input') { $dslCell["controlType"] = $name } if ($name -cne 'input') { $dslCell["controlType"] = $name }
} }
if ($null -ne $cell.Value) {
$dslCell["value"] = ConvertTo-DslValue $cell.Value.Type $cell.Value.Text
}
if ($cell.Control) { $dslCell["control"] = $cell.Control }
} }
# Content # Content
@@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# mxl-decompile v1.21 — Decompile 1C spreadsheet to JSON # mxl-decompile v1.22 — Decompile 1C spreadsheet to JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse import argparse
@@ -187,6 +187,23 @@ def value_type_to_dsl(node):
return ' + '.join(parts) return ' + '.join(parts)
def value_to_dsl(xsi_type, text):
"""Значение ячейки-поля ввода → литерал DSL. Тип значения выражается самим литералом:
число → числом, булево → true/false, строка и дата → строкой. Пустое значение пишем
как есть (0, false, пустая дата), а не схлопываем: так оно собирается обратно тем же
типом независимо от того, какой тип объявлен у ячейки."""
text = text or ''
if xsi_type == 'xs:boolean':
return text.strip() == 'true'
if xsi_type == 'xs:decimal':
s = text.strip()
try:
return int(s) if '.' not in s else float(s)
except ValueError:
return s
return text
def int_of(node, default=0): def int_of(node, default=0):
if node is not None and node.text: if node is not None and node.text:
return int(node.text) return int(node.text)
@@ -556,6 +573,22 @@ def main():
if d_node is not None and d_node.text: if d_node is not None and d_node.text:
detail = d_node.text detail = d_node.text
# Значение ячейки-поля ввода. Тип значения свой, из объявленного не выводится,
# поэтому читаем и его: пустое значение сворачивается в "", остальные едут как есть.
value = None
v_node = find(c_content, "d:v")
if v_node is not None:
value = (v_node.get(f'{{{XSI_NS}}}type') or '', (v_node.text or ''))
# Настройки элемента управления — сериализованный base64 у самой ячейки.
# Структуру не разбираем, возим дословно.
control = None
ctl_node = find(c_content, "d:control")
if ctl_node is not None and ctl_node.text:
# Переводы строк внутри блоба приводим к LF: XML-парсеры нормализуют их
# по-разному, и без этого порты давали разный JSON на одном файле.
control = ctl_node.text.replace('\r\n', '\n')
# Текст ячейки платформа хранит по элементу на язык. Раньше брался ПЕРВЫЙ, и всё # Текст ячейки платформа хранит по элементу на язык. Раньше брался ПЕРВЫЙ, и всё
# остальное терялось — в корпусе ERP 98% макетов держат текст и под ru, и под en. # остальное терялось — в корпусе ERP 98% макетов держат текст и под ru, и под en.
# Здесь собираем «язык → текст» как есть; свернётся в строку позже, когда станет # Здесь собираем «язык → текст» как есть; свернётся в строку позже, когда станет
@@ -587,6 +620,8 @@ def main():
"FormatIdx": cell_fmt_idx, "FormatIdx": cell_fmt_idx,
"Param": param, "Param": param,
"Detail": detail, "Detail": detail,
"Value": value,
"Control": control,
"Text": text, "Text": text,
"HasText": has_text, "HasText": has_text,
}) })
@@ -1128,6 +1163,10 @@ def main():
# форматах корпуса. # форматах корпуса.
if name != "input": if name != "input":
dsl_cell["controlType"] = name dsl_cell["controlType"] = name
if cell["Value"] is not None:
dsl_cell["value"] = value_to_dsl(*cell["Value"])
if cell["Control"]:
dsl_cell["control"] = cell["Control"]
# Content # Content
fill_type = cell_fmt["FillType"] if cell_fmt else "" fill_type = cell_fmt["FillType"] if cell_fmt else ""
+17 -3
View File
@@ -152,7 +152,8 @@
| `{ ... }` | Обычная ячейка **без** `col`; нужна для `style`, `detail`, `template` | | `{ ... }` | Обычная ячейка **без** `col`; нужна для `style`, `detail`, `template` |
Объект-элемент трактуется по его ключам: если среди них есть ключ ячейки (`span`, `rowspan`, Объект-элемент трактуется по его ключам: если среди них есть ключ ячейки (`span`, `rowspan`,
`style`, `param`, `detail`, `text`, `template`, `valueType`, `controlType`) — объект описывает `style`, `param`, `detail`, `text`, `template`, `valueType`, `controlType`, `value`) — объект
описывает
свойства ячейки. Иначе он целиком считается её текстом, а его ключи — идентификаторами языков. свойства ячейки. Иначе он целиком считается её текстом, а его ключи — идентификаторами языков.
```json ```json
@@ -184,6 +185,7 @@
| `template` | нет | — | Шаблонный текст с `[Параметр]`. Строка или объект, как `text` | | `template` | нет | — | Шаблонный текст с `[Параметр]`. Строка или объект, как `text` |
| `valueType` | нет | — | Тип значения: ячейка становится полем ввода (см. ниже) | | `valueType` | нет | — | Тип значения: ячейка становится полем ввода (см. ниже) |
| `controlType` | нет | `input` | Элемент управления поля ввода: `input` или `checkbox`. Только вместе с `valueType` | | `controlType` | нет | `input` | Элемент управления поля ввода: `input` или `checkbox`. Только вместе с `valueType` |
| `value` | нет | — | Значение в поле ввода. Только вместе с `valueType` |
### Содержимое ячейки ### Содержимое ячейки
@@ -248,6 +250,20 @@
Пустой тип `"valueType": ""` — «ячейка содержит значение», но тип не ограничен. Пустой тип `"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` нужен редко: умолчание платформы — поле ввода, и оно применяется ко всем типам, `controlType` нужен редко: умолчание платформы — поле ввода, и оно применяется ко всем типам,
включая `Boolean`. Флажок задаётся явно. Значение `"none"` (тега элемента управления нет вовсе) — включая `Boolean`. Флажок задаётся явно. Значение `"none"` (тега элемента управления нет вовсе) —
форма раундтрипа, для ручного авторинга не нужна. форма раундтрипа, для ручного авторинга не нужна.
@@ -266,8 +282,6 @@ DSL описывает не все конструкции табличного
round-trip** (`/mxl-decompile``/mxl-compile`): в JSON оно не попадает, в сгенерированный round-trip** (`/mxl-decompile``/mxl-compile`): в JSON оно не попадает, в сгенерированный
XML не возвращается. XML не возвращается.
- начальное значение ячейки-поля ввода и сериализованные настройки её элемента управления
(тип значения при этом переживает цикл);
- объединения, не привязанные к ячейке (по всей высоте или ширине документа); - объединения, не привязанные к ячейке (по всей высоте или ширине документа);
- рисунки и картинки, в том числе штрихкоды, и примечания к ячейкам; - рисунки и картинки, в том числе штрихкоды, и примечания к ячейкам;
- группировки строк и колонок; - группировки строк и колонок;
@@ -0,0 +1,14 @@
{
"name": "Ошибка: value без valueType",
"input": {
"columns": 1,
"areas": [
{
"name": "Ввод",
"rows": [{ "cells": [{ "col": 1, "value": "5" }] }]
}
]
},
"params": { "outputPath": "Template.xml" },
"expectError": "Cell 'value' requires 'valueType' (area \"Ввод\")"
}
@@ -112,10 +112,129 @@
</c> </c>
</row> </row>
</rowsItem> </rowsItem>
<rowsItem>
<index>7</index>
<row>
<c>
<c>
<f>3</f>
<v xsi:type="xs:string">5</v>
</c>
</c>
<c>
<c>
<f>2</f>
<v xsi:type="xs:decimal">8</v>
</c>
</c>
</row>
</rowsItem>
<rowsItem>
<index>8</index>
<row>
<c>
<c>
<f>3</f>
<v xsi:type="xs:string">4 5</v>
</c>
</c>
<c>
<c>
<f>2</f>
<v xsi:type="xs:decimal">0</v>
</c>
</c>
<c>
<c>
<f>12</f>
<v xsi:type="xs:dateTime">0001-01-01T00:00:00</v>
</c>
</c>
</row>
</rowsItem>
<rowsItem>
<index>9</index>
<row>
<c>
<c>
<f>13</f>
<v xsi:type="xs:string">4 5</v>
</c>
</c>
<c>
<c>
<f>12</f>
<v xsi:type="xs:dateTime">0001-01-01T00:00:00</v>
</c>
</c>
<c>
<c>
<f>4</f>
<v xsi:type="xs:boolean">true</v>
</c>
</c>
</row>
</rowsItem>
<rowsItem>
<index>10</index>
<row>
<c>
<c>
<f>14</f>
<v xsi:type="xs:string">Составной</v>
</c>
</c>
<c>
<c>
<f>2</f>
<v xsi:type="xs:decimal">12.5</v>
</c>
</c>
<c>
<c>
<f>2</f>
<v xsi:type="xs:decimal">-3</v>
</c>
</c>
</row>
</rowsItem>
<rowsItem>
<index>11</index>
<row>
<c>
<c>
<f>15</f>
</c>
</c>
<c>
<c>
<f>12</f>
<v xsi:type="xs:dateTime">0001-01-01T00:00:00</v>
</c>
</c>
<c>
<c>
<f>3</f>
<control xsi:type="xs:base64Binary">77u/MiwxLDM4MWVkNjI0LTkyMTctNGU2My04NWRiLWM0YzNjYjg3ZGFhZSwNCnsN
Cns5LA0KeyJQYXR0ZXJuIiwNCnsiUyJ9DQp9LA0Kew0Kew0KezE2LDEsDQp7Myw0
LA0KezB9DQp9LA0KezMsNCwNCnswfQ0KfSwNCns3LDMsMCwxLDEwMH0sMCwNCnsz
LDQsDQp7MH0NCn0sDQp7Myw0LA0KezB9DQp9LA0KezMsNCwNCnswfQ0KfSwNCnsz
LDMsDQp7LTd9DQp9LA0KezMsMywNCnstMjF9DQp9LA0KezMsMSwNCnstMTh9LDAs
MCwwfSwNCnsxLDB9LDAsMCwxMDAsMCwwfSwzMCwwLDAsMSwwLDAsMSwxLDEsMCwx
LDAsMCwwLDAsMCw0LDAsDQp7IlUifSwNCnsiVSJ9LCIiLDAsMSwwLDAsMCwwLA0K
ezQsMCwNCnswfSwiIiwtMSwtMSwxLDAsIiJ9LA0KezQsMCwNCnswfSwiIiwtMSwt
MSwxLDAsIiJ9LDAsMCwwLA0KezAsMCwwfSwNCnsxLDB9LDAsMCwwLDAsMCwwLDAs
MTY3NzcyMTUsMn0NCn0sDQp7MSwNCns5YTc2NDNkMi0xOWU5LTQ1ZTItODg5My0y
ODBiYzkxOTVhOTcsDQp7NCwNCnsiVSJ9LA0KeyJVIn0sMCwiIiwwLDB9DQp9DQp9
LA0KezB9LDAsMSwwLA0KezEsMH0sMH0NCn0sMA==</control>
</c>
</c>
</row>
</rowsItem>
<templateMode>true</templateMode> <templateMode>true</templateMode>
<defaultFormatIndex>12</defaultFormatIndex> <defaultFormatIndex>16</defaultFormatIndex>
<height>7</height> <height>12</height>
<vgRows>7</vgRows> <vgRows>12</vgRows>
<format> <format>
<containsValue>true</containsValue> <containsValue>true</containsValue>
<valueType> <valueType>
@@ -232,6 +351,57 @@
</valueType> </valueType>
<controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType> <controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType>
</format> </format>
<format>
<containsValue>true</containsValue>
<valueType>
<v8:Type>xs:dateTime</v8:Type>
<v8:DateQualifiers>
<v8:DateFractions>DateTime</v8:DateFractions>
</v8:DateQualifiers>
</valueType>
<controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType>
</format>
<format>
<containsValue>true</containsValue>
<valueType>
<v8:Type xmlns:d4p1="http://v8.1c.ru/8.1/data/enterprise/current-config">d4p1:CatalogRef.Бригады</v8:Type>
</valueType>
<controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType>
</format>
<format>
<containsValue>true</containsValue>
<valueType>
<v8:Type>xs:boolean</v8:Type>
<v8:Type>xs:string</v8:Type>
<v8:Type>xs:dateTime</v8:Type>
<v8:Type>xs:decimal</v8:Type>
<v8:NumberQualifiers>
<v8:Digits>0</v8:Digits>
<v8:FractionDigits>0</v8:FractionDigits>
<v8:AllowedSign>Any</v8:AllowedSign>
</v8:NumberQualifiers>
<v8:StringQualifiers>
<v8:Length>0</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
<v8:DateQualifiers>
<v8:DateFractions>DateTime</v8:DateFractions>
</v8:DateQualifiers>
</valueType>
<controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType>
</format>
<format>
<containsValue>true</containsValue>
<valueType>
<v8:Type>xs:decimal</v8:Type>
<v8:NumberQualifiers>
<v8:Digits>0</v8:Digits>
<v8:FractionDigits>0</v8:FractionDigits>
<v8:AllowedSign>Any</v8:AllowedSign>
</v8:NumberQualifiers>
</valueType>
<controlType>35af3d93-d7c7-4a2e-a8eb-bac87a1a3f26</controlType>
</format>
<format> <format>
<width>72</width> <width>72</width>
</format> </format>
@@ -0,0 +1,225 @@
<?xml version="1.0" encoding="UTF-8"?>
<document xmlns="http://v8.1c.ru/8.2/data/spreadsheet" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<languageSettings>
<currentLanguage>ru</currentLanguage>
<defaultLanguage>ru</defaultLanguage>
<languageInfo>
<id>ru</id>
<code>Русский</code>
<description>Русский</description>
</languageInfo>
</languageSettings>
<columns>
<size>3</size>
</columns>
<rowsItem>
<index>0</index>
<row>
<c>
<c>
<f>1</f>
<v xsi:type="xs:string">5</v>
</c>
</c>
<c>
<c>
<f>2</f>
<v xsi:type="xs:decimal">12.5</v>
</c>
</c>
<c>
<c>
<f>3</f>
<v xsi:type="xs:decimal">-3</v>
</c>
</c>
</row>
</rowsItem>
<rowsItem>
<index>1</index>
<row>
<c>
<c>
<f>4</f>
<v xsi:type="xs:boolean">true</v>
</c>
</c>
<c>
<c>
<f>4</f>
<v xsi:type="xs:boolean">false</v>
</c>
</c>
<c>
<c>
<f>5</f>
<v xsi:type="xs:dateTime">2026-08-09T13:45:00</v>
</c>
</c>
</row>
</rowsItem>
<rowsItem>
<index>2</index>
<row>
<c>
<c>
<f>6</f>
<v xsi:type="xs:string"></v>
</c>
</c>
<c>
<c>
<f>7</f>
<v xsi:type="xs:decimal">0</v>
</c>
</c>
<c>
<c>
<f>5</f>
<v xsi:type="xs:dateTime">0001-01-01T00:00:00</v>
</c>
</c>
</row>
</rowsItem>
<rowsItem>
<index>3</index>
<row>
<c>
<c>
<f>8</f>
<v xsi:type="xs:string">4 5</v>
</c>
</c>
<c>
<c>
<f>9</f>
<v xsi:type="xs:string">Составной</v>
</c>
</c>
<c>
<c>
<f>3</f>
<v xsi:type="xs:decimal">8</v>
<detailParameter>Расшифровка</detailParameter>
</c>
</c>
</row>
</rowsItem>
<templateMode>true</templateMode>
<defaultFormatIndex>10</defaultFormatIndex>
<height>4</height>
<vgRows>4</vgRows>
<namedItem xsi:type="NamedItemCells">
<name>Значения</name>
<area>
<type>Rows</type>
<beginRow>0</beginRow>
<endRow>3</endRow>
<beginColumn>-1</beginColumn>
<endColumn>-1</endColumn>
</area>
</namedItem>
<format>
<containsValue>true</containsValue>
<valueType>
<v8:Type>xs:string</v8:Type>
<v8:StringQualifiers>
<v8:Length>10</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
<controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType>
</format>
<format>
<containsValue>true</containsValue>
<valueType>
<v8:Type>xs:decimal</v8:Type>
<v8:NumberQualifiers>
<v8:Digits>15</v8:Digits>
<v8:FractionDigits>3</v8:FractionDigits>
<v8:AllowedSign>Any</v8:AllowedSign>
</v8:NumberQualifiers>
</valueType>
<controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType>
</format>
<format>
<containsValue>true</containsValue>
<valueType>
<v8:Type>xs:decimal</v8:Type>
<v8:NumberQualifiers>
<v8:Digits>10</v8:Digits>
<v8:FractionDigits>2</v8:FractionDigits>
<v8:AllowedSign>Any</v8:AllowedSign>
</v8:NumberQualifiers>
</valueType>
<controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType>
</format>
<format>
<containsValue>true</containsValue>
<valueType>
<v8:Type>xs:boolean</v8:Type>
</valueType>
<controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType>
</format>
<format>
<containsValue>true</containsValue>
<valueType>
<v8:Type>xs:dateTime</v8:Type>
<v8:DateQualifiers>
<v8:DateFractions>DateTime</v8:DateFractions>
</v8:DateQualifiers>
</valueType>
<controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType>
</format>
<format>
<containsValue>true</containsValue>
<valueType>
<v8:Type>xs:string</v8:Type>
<v8:StringQualifiers>
<v8:Length>0</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
<controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType>
</format>
<format>
<containsValue>true</containsValue>
<valueType>
<v8:Type>xs:decimal</v8:Type>
<v8:NumberQualifiers>
<v8:Digits>0</v8:Digits>
<v8:FractionDigits>0</v8:FractionDigits>
<v8:AllowedSign>Any</v8:AllowedSign>
</v8:NumberQualifiers>
</valueType>
<controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType>
</format>
<format>
<containsValue>true</containsValue>
<valueType>
<v8:Type xmlns:d4p1="http://v8.1c.ru/8.1/data/enterprise/current-config">d4p1:CatalogRef.Валюты</v8:Type>
</valueType>
<controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType>
</format>
<format>
<containsValue>true</containsValue>
<valueType>
<v8:Type>xs:boolean</v8:Type>
<v8:Type>xs:string</v8:Type>
<v8:Type>xs:decimal</v8:Type>
<v8:NumberQualifiers>
<v8:Digits>0</v8:Digits>
<v8:FractionDigits>0</v8:FractionDigits>
<v8:AllowedSign>Any</v8:AllowedSign>
</v8:NumberQualifiers>
<v8:StringQualifiers>
<v8:Length>0</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
<controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType>
</format>
<format>
<width>10</width>
</format>
</document>
@@ -0,0 +1,37 @@
{
"name": "Ячейки-поля ввода: сохранённое значение",
"input": {
"columns": 3,
"areas": [
{
"name": "Значения",
"rows": [
{ "cells": [
{ "col": 1, "valueType": "String(10)", "value": "5" },
{ "col": 2, "valueType": "Number(15,3)", "value": 12.5 },
{ "col": 3, "valueType": "Number(10,2)", "value": -3 }
]},
{ "cells": [
{ "col": 1, "valueType": "Boolean", "value": true },
{ "col": 2, "valueType": "Boolean", "value": false },
{ "col": 3, "valueType": "DateTime", "value": "2026-08-09T13:45:00" }
]},
{ "cells": [
{ "col": 1, "valueType": "String", "value": "" },
{ "col": 2, "valueType": "Number", "value": "" },
{ "col": 3, "valueType": "DateTime", "value": "" }
]},
{ "cells": [
{ "col": 1, "valueType": "CatalogRef.Валюты", "value": "4 5" },
{ "col": 2, "valueType": "Boolean + String + Number", "value": "Составной" },
{ "col": 3, "valueType": "Number(10,2)", "value": 8, "detail": "Расшифровка" }
]}
]
}
]
},
"params": {
"outputPath": "Template.xml"
},
"skipPlatformVerify": "ссылочный тип разрешается только в базе с матч-конфигурацией: временная база-заглушка таких объектов не содержит"
}
@@ -0,0 +1,41 @@
{
"name": "Roundtrip — сохранённые значения ячеек-полей ввода",
"preRun": [
{
"script": "mxl-compile/scripts/mxl-compile",
"input": {
"columns": 3,
"areas": [
{
"name": "Значения",
"rows": [
{ "cells": [
{ "col": 1, "valueType": "String(10)", "value": "5" },
{ "col": 2, "valueType": "Number(15,3)", "value": 12.5 },
{ "col": 3, "valueType": "Number(10,2)", "value": -3 }
]},
{ "cells": [
{ "col": 1, "valueType": "Boolean", "value": true },
{ "col": 2, "valueType": "DateTime", "value": "2026-08-09T13:45:00" },
{ "col": 3, "valueType": "DateTime", "value": "" }
]},
{ "cells": [
{ "col": 1, "valueType": "String", "value": "" },
{ "col": 2, "valueType": "Number", "value": "" },
{ "col": 3, "valueType": "Boolean + String + Number", "value": "Составной" }
]}
]
}
]
},
"args": { "-JsonPath": "{inputFile}", "-OutputPath": "Template.xml" },
"cwd": "{workDir}"
}
],
"params": { "templatePath": "Template.xml" },
"args_extra": ["-OutputPath", "{workDir}/back.json"],
"expect": {
"files": ["back.json"],
"stdoutContains": "[OK] Decompiled:"
}
}
@@ -0,0 +1,194 @@
<?xml version="1.0" encoding="UTF-8"?>
<document xmlns="http://v8.1c.ru/8.2/data/spreadsheet" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<languageSettings>
<currentLanguage>ru</currentLanguage>
<defaultLanguage>ru</defaultLanguage>
<languageInfo>
<id>ru</id>
<code>Русский</code>
<description>Русский</description>
</languageInfo>
</languageSettings>
<columns>
<size>3</size>
</columns>
<rowsItem>
<index>0</index>
<row>
<c>
<c>
<f>1</f>
<v xsi:type="xs:string">5</v>
</c>
</c>
<c>
<c>
<f>2</f>
<v xsi:type="xs:decimal">12.5</v>
</c>
</c>
<c>
<c>
<f>3</f>
<v xsi:type="xs:decimal">-3</v>
</c>
</c>
</row>
</rowsItem>
<rowsItem>
<index>1</index>
<row>
<c>
<c>
<f>4</f>
<v xsi:type="xs:boolean">true</v>
</c>
</c>
<c>
<c>
<f>5</f>
<v xsi:type="xs:dateTime">2026-08-09T13:45:00</v>
</c>
</c>
<c>
<c>
<f>5</f>
<v xsi:type="xs:dateTime">0001-01-01T00:00:00</v>
</c>
</c>
</row>
</rowsItem>
<rowsItem>
<index>2</index>
<row>
<c>
<c>
<f>6</f>
<v xsi:type="xs:string"></v>
</c>
</c>
<c>
<c>
<f>7</f>
<v xsi:type="xs:decimal">0</v>
</c>
</c>
<c>
<c>
<f>8</f>
<v xsi:type="xs:string">Составной</v>
</c>
</c>
</row>
</rowsItem>
<templateMode>true</templateMode>
<defaultFormatIndex>9</defaultFormatIndex>
<height>3</height>
<vgRows>3</vgRows>
<namedItem xsi:type="NamedItemCells">
<name>Значения</name>
<area>
<type>Rows</type>
<beginRow>0</beginRow>
<endRow>2</endRow>
<beginColumn>-1</beginColumn>
<endColumn>-1</endColumn>
</area>
</namedItem>
<format>
<containsValue>true</containsValue>
<valueType>
<v8:Type>xs:string</v8:Type>
<v8:StringQualifiers>
<v8:Length>10</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
<controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType>
</format>
<format>
<containsValue>true</containsValue>
<valueType>
<v8:Type>xs:decimal</v8:Type>
<v8:NumberQualifiers>
<v8:Digits>15</v8:Digits>
<v8:FractionDigits>3</v8:FractionDigits>
<v8:AllowedSign>Any</v8:AllowedSign>
</v8:NumberQualifiers>
</valueType>
<controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType>
</format>
<format>
<containsValue>true</containsValue>
<valueType>
<v8:Type>xs:decimal</v8:Type>
<v8:NumberQualifiers>
<v8:Digits>10</v8:Digits>
<v8:FractionDigits>2</v8:FractionDigits>
<v8:AllowedSign>Any</v8:AllowedSign>
</v8:NumberQualifiers>
</valueType>
<controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType>
</format>
<format>
<containsValue>true</containsValue>
<valueType>
<v8:Type>xs:boolean</v8:Type>
</valueType>
<controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType>
</format>
<format>
<containsValue>true</containsValue>
<valueType>
<v8:Type>xs:dateTime</v8:Type>
<v8:DateQualifiers>
<v8:DateFractions>DateTime</v8:DateFractions>
</v8:DateQualifiers>
</valueType>
<controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType>
</format>
<format>
<containsValue>true</containsValue>
<valueType>
<v8:Type>xs:string</v8:Type>
<v8:StringQualifiers>
<v8:Length>0</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
<controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType>
</format>
<format>
<containsValue>true</containsValue>
<valueType>
<v8:Type>xs:decimal</v8:Type>
<v8:NumberQualifiers>
<v8:Digits>0</v8:Digits>
<v8:FractionDigits>0</v8:FractionDigits>
<v8:AllowedSign>Any</v8:AllowedSign>
</v8:NumberQualifiers>
</valueType>
<controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType>
</format>
<format>
<containsValue>true</containsValue>
<valueType>
<v8:Type>xs:boolean</v8:Type>
<v8:Type>xs:string</v8:Type>
<v8:Type>xs:decimal</v8:Type>
<v8:NumberQualifiers>
<v8:Digits>0</v8:Digits>
<v8:FractionDigits>0</v8:FractionDigits>
<v8:AllowedSign>Any</v8:AllowedSign>
</v8:NumberQualifiers>
<v8:StringQualifiers>
<v8:Length>0</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
<controlType>381ed624-9217-4e63-85db-c4c3cb87daae</controlType>
</format>
<format>
<width>10</width>
</format>
</document>
@@ -0,0 +1,16 @@
{
"columns": 3,
"defaultWidth": 10,
"fonts": {},
"styles": {},
"areas": [
{
"name": "Значения",
"rows": [
[{ "valueType": "String(10)", "value": "5" }, { "valueType": "Number(15,3)", "value": 12.5 }, { "valueType": "Number(10,2)", "value": -3 }],
[{ "valueType": "Boolean", "value": true }, { "valueType": "DateTime", "value": "2026-08-09T13:45:00" }, { "valueType": "DateTime", "value": "0001-01-01T00:00:00" }],
[{ "valueType": "String", "value": "" }, { "valueType": "Number", "value": 0 }, { "valueType": "Boolean + String + Number", "value": "Составной" }]
]
}
]
}