feat(mxl-compile,mxl-decompile): пустой тег текста ячейки

У текста ячейки три состояния, а выражались два: тега нет вовсе, тег с пустым
текстом на каждый язык — и третье, <tl/>, которое мы теряли. Это не редкость:
38 075 ячеек на 1200 макетов, встречается в 57% макетов корпуса.

Выражается пустым объектом: "text": {}. Не новый ключ и не новое понятие, а
вырожденный случай уже принятой записи «язык → текст» — языков нет вовсе.
В позиционной строке двусмысленности не создаёт: {} не несёт ключей ячейки,
значит по общему правилу читается как текст, а null там по-прежнему «пропустить
колонку».

В описании DSL записи нет намеренно. Для авторинга она бесполезна — визуально
это тот же пустой текст, что и "", — а документировать две пустые формы рядом
значило бы завести развилку, у которой нет правильного ответа.

Платформа пишет такой тег самозакрывающимся, поэтому эмиссия отдельной веткой.

На пилоте потери в категории row[].cell[].tl упали с 12 488 до 2, заодно
row[].cell[].fmt с 41 645 до 30 088; совпадение строк документа 17.6% → 18.5%.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-08-12 12:21:02 +03:00
co-authored by Claude Opus 5
parent 6619a4e7ad
commit 0a8671a166
4 changed files with 31 additions and 6 deletions
@@ -1,4 +1,4 @@
# mxl-compile v1.38 — Compile 1C spreadsheet from JSON
# mxl-compile v1.39 — Compile 1C spreadsheet from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -800,6 +800,13 @@ function Emit-CellText {
} else {
foreach ($l in $textLanguages) { $pairs += @{ Lang = $l; Text = "$value" } }
}
# Пустой объект — отдельное состояние: тег текста есть, языков в нём нет. Платформа
# пишет его самозакрывающимся. Для авторинга бесполезно (визуально это тот же пустой
# текст, что и ""), поэтому в описании DSL записи нет — она нужна раундтрипу.
if ($pairs.Count -eq 0) {
X "`t`t`t`t`t<tl/>"
return
}
X "`t`t`t`t`t<tl>"
foreach ($p in $pairs) {
X "`t`t`t`t`t`t<v8:item>"
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# mxl-compile v1.37 — Compile 1C spreadsheet from JSON
# mxl-compile v1.38 — Compile 1C spreadsheet from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import hashlib
@@ -850,6 +850,12 @@ def main():
pairs = [(str(k), str(v)) for k, v in value.items()]
else:
pairs = [(lang, str(value)) for lang in text_languages]
# Пустой объект — отдельное состояние: тег текста есть, языков в нём нет. Платформа
# пишет его самозакрывающимся. Для авторинга бесполезно (визуально это тот же пустой
# текст, что и ""), поэтому в описании DSL записи нет — она нужна раундтрипу.
if not pairs:
lines.append('\t\t\t\t\t<tl/>')
return
lines.append('\t\t\t\t\t<tl>')
for lang, content in pairs:
lines.append('\t\t\t\t\t\t<v8:item>')
@@ -1,4 +1,4 @@
# mxl-decompile v1.18 — Decompile 1C spreadsheet to JSON
# mxl-decompile v1.19 — Decompile 1C spreadsheet to JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -314,8 +314,14 @@ foreach ($riNode in $root.SelectNodes("d:rowsItem", $ns)) {
# известен набор языков всего макета (Get-DslText).
$text = $null
$hasText = $false
# Пустой <tl/> — отдельное состояние: тег текста есть, языков в нём нет. Без
# этого ветвления такая ячейка теряла текст вовсе (1 из 15 ячеек с тегом текста).
$tlNode = $cContent.SelectSingleNode("d:tl", $ns)
$items = $cContent.SelectNodes("d:tl/v8:item", $ns)
if ($items -and $items.Count -gt 0) {
if ($tlNode -and (-not $items -or $items.Count -eq 0)) {
$text = [ordered]@{}
$hasText = $true
} elseif ($items -and $items.Count -gt 0) {
$byLang = [ordered]@{}
foreach ($it in $items) {
$langNode = $it.SelectSingleNode("v8:lang", $ns)
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# mxl-decompile v1.18 — Decompile 1C spreadsheet to JSON
# mxl-decompile v1.19 — Decompile 1C spreadsheet to JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -483,8 +483,14 @@ def main():
# известен набор языков всего макета (get_dsl_text).
text = None
has_text = False
# Пустой <tl/> — отдельное состояние: тег текста есть, языков в нём нет. Без
# этого ветвления такая ячейка теряла текст вовсе (1 из 15 ячеек с тегом текста).
tl_node = find(c_content, "d:tl")
items = findall(c_content, "d:tl/v8:item")
if items:
if tl_node is not None and not items:
text = OrderedDict()
has_text = True
elif items:
by_lang = OrderedDict()
for it in items:
lang_node = find(it, "v8:lang")