mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-08-18 09:10:21 +03:00
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:
co-authored by
Claude Opus 5
parent
66bb285636
commit
43d2f660da
@@ -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
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
@@ -854,6 +854,14 @@ function Get-CellValueProps {
|
||||
[Console]::Error.WriteLine("Cell 'controlType' requires 'valueType' ($where)")
|
||||
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
|
||||
}
|
||||
# Ячейка, содержащая значение, текста не несёт: платформа этого не допускает, и в корпусе
|
||||
@@ -885,6 +893,46 @@ function Get-CellValueProps {
|
||||
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 ---
|
||||
|
||||
$formatRegistry = [ordered]@{} # key -> hashtable with properties
|
||||
@@ -1140,7 +1188,7 @@ function Set-CellProp {
|
||||
function Test-CellObject {
|
||||
param($el)
|
||||
$cellKeys = @('col', 'span', 'rowspan', 'style', 'param', 'detail', 'text', 'template',
|
||||
'valueType', 'controlType')
|
||||
'valueType', 'controlType', 'value', 'control')
|
||||
foreach ($p in $el.PSObject.Properties) {
|
||||
if ($cellKeys -contains $p.Name) { return $true }
|
||||
}
|
||||
@@ -1613,6 +1661,8 @@ foreach ($area in $def.areas) {
|
||||
Detail = $cell.detail
|
||||
Text = $cell.text
|
||||
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
|
||||
|
||||
@@ -1719,6 +1769,22 @@ foreach ($area in $def.areas) {
|
||||
|
||||
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 ячейки несут
|
||||
# её БЕЗ параметра (у текста, у пустой ячейки, у поля ввода) против 8 582 с ним.
|
||||
# Пока она стояла внутри ветки параметра, две трети расшифровок терялись молча.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/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
|
||||
import argparse
|
||||
import hashlib
|
||||
@@ -644,6 +644,45 @@ def emit_value_type_content(lines, indent, canon_type):
|
||||
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):
|
||||
"""Свойства значения ячейки — пустой набор, если ячейка обычная. Считаются ОДНОЙ функцией:
|
||||
пре-проход регистрации палитры и генерация обязаны получить один и тот же набор, иначе
|
||||
@@ -655,6 +694,12 @@ def cell_value_props(cell, where):
|
||||
if ctl is not None and str(ctl) != '':
|
||||
print(f"Cell 'controlType' requires 'valueType' ({where})", file=sys.stderr)
|
||||
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
|
||||
# Ячейка, содержащая значение, текста не несёт: платформа этого не допускает, и в корпусе
|
||||
# нет ни одной такой ячейки из 370 197.
|
||||
@@ -1154,7 +1199,7 @@ def main():
|
||||
ключей есть ключ схемы ячейки, во втором ключи — идентификаторы языков. Пересечений
|
||||
нет: в корпусе это ru, en, ru1, Русский."""
|
||||
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)
|
||||
|
||||
def expand_shorthand_row(row, area_name, row_idx, open_by_col, max_cols):
|
||||
@@ -1570,6 +1615,9 @@ def main():
|
||||
'Detail': cell.get('detail'),
|
||||
'Text': cell.get('text'),
|
||||
'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)
|
||||
|
||||
@@ -1667,6 +1715,21 @@ def main():
|
||||
if cell_info['Template'] is not None:
|
||||
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 ячейки несут
|
||||
# её БЕЗ параметра (у текста, у пустой ячейки, у поля ввода) против 8 582 с ним.
|
||||
# Пока она стояла внутри ветки параметра, две трети расшифровок терялись молча.
|
||||
|
||||
Reference in New Issue
Block a user