fix(form,skd,init,meta-edit): развести экранирование атрибута и текста

esc_xml был один на две задачи, и в атрибутном контексте применялся текстовый
вариант без ". form-compile с choiceParameters, имя которого содержит
кавычку, выдавал <app:item name="Отбор.Наименование "кавычка"">: lxml падает с
attributes construct error, то есть файл невалиден как XML. Затронуто 9 мест в
form-compile и 3 в skd-compile, одинаково в обоих портах.

Раундтрип через базу показал границу: в ТЕКСТЕ элемента платформа экранирует
только & < > (кавычка и апостроф возвращаются сырыми байт-в-байт), а в ЗНАЧЕНИИ
АТРИБУТА пишет &quot; — внутри "..." литеральная кавычка невалидна. Поэтому две
функции с говорящими именами, а не одна с флагом:
  esc_xml      — значение атрибута: & < > "
  esc_xml_text — текст элемента:    & < >

Заодно закрыто расхождение портов в init-навыках: PY экранировал текст с &quot;,
PS1 — через SecurityElement::Escape (ещё и &apos;), а epf-init/erf-init в PS1 не
экранировали вовсе, из-за чего амперсанд в синониме давал невалидный XML.

Кейсы: form-compile/attr-value-escaping, skd-compile/additional-properties-escaping,
cf-init/synonym-escaping — все три проверены негативным прогоном на обоих портах
и верификацией снэпшотов на платформе.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-08-08 20:53:12 +03:00
co-authored by Claude Opus 5
parent 3c50d3caa0
commit 974ca3aac9
43 changed files with 1818 additions and 882 deletions
@@ -1,4 +1,4 @@
# subsystem-edit v1.15 — Edit existing 1C subsystem XML
# subsystem-edit v1.16 — Edit existing 1C subsystem XML (+esc_xml/esc_xml_text: разное экранирование атрибута и текста)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)][Alias('Path')][string]$SubsystemPath,
@@ -320,9 +320,15 @@ foreach ($child in $script:propsEl.ChildNodes) {
Info "Subsystem: $($script:objName)"
# --- XML manipulation helpers (from meta-edit pattern) ---
function Esc-Xml([string]$s) {
# Экранирование ТЕКСТА элемента: только & < > . Кавычки в тексте платформа НЕ экранирует —
# пишет литерально (92142 сырых кавычки на корпус, ни одной &quot;).
function Esc-Xml {
param([string]$s)
# Эскейп ЗНАЧЕНИЯ АТРИБУТА: & < > и кавычка — внутри "..." литеральная " невалидна.
return $s.Replace('&','&amp;').Replace('<','&lt;').Replace('>','&gt;').Replace('"','&quot;')
}
function Esc-XmlText {
param([string]$s)
# Эскейп ТЕКСТА элемента: только & < > — кавычку и апостроф платформа держит сырыми.
return $s.Replace('&','&amp;').Replace('<','&lt;').Replace('>','&gt;')
}
@@ -337,7 +343,7 @@ function Write-ChildSubsystemStub([string]$childPath, [string]$childName, [strin
[void]$sb.AppendLine("<MetaDataObject $($script:xmlnsDecl) version=`"$formatVersion`">")
[void]$sb.AppendLine("`t<Subsystem uuid=`"$childUuid`">")
[void]$sb.AppendLine("`t`t<Properties>")
[void]$sb.AppendLine("`t`t`t<Name>$(Esc-Xml $childName)</Name>")
[void]$sb.AppendLine("`t`t`t<Name>$(Esc-XmlText $childName)</Name>")
[void]$sb.AppendLine("`t`t`t<Synonym/>")
[void]$sb.AppendLine("`t`t`t<Comment/>")
[void]$sb.AppendLine("`t`t`t<IncludeHelpInContents>true</IncludeHelpInContents>")
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# subsystem-edit v1.15 — Edit existing 1C subsystem XML
# subsystem-edit v1.16 — Edit existing 1C subsystem XML (+esc_xml/esc_xml_text: разное экранирование атрибута и текста)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -193,6 +193,11 @@ def new_uuid():
def esc_xml(s):
# Эскейп ЗНАЧЕНИЯ АТРИБУТА: & < > и кавычка — внутри "..." литеральная " невалидна.
return s.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;')
def esc_xml_text(s):
"""Экранирование ТЕКСТА элемента: только & < > . Кавычки платформа в тексте не экранирует
(92142 сырых кавычки на корпус, ни одной &quot;); &quot; она принимает, но нормализует обратно."""
return s.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
@@ -250,7 +255,7 @@ def write_child_subsystem_stub(child_path, child_name, format_version):
lines.append(f'<MetaDataObject {XMLNS_DECL} version="{format_version}">')
lines.append(f'\t<Subsystem uuid="{child_uuid}">')
lines.append('\t\t<Properties>')
lines.append(f'\t\t\t<Name>{esc_xml(child_name)}</Name>')
lines.append(f'\t\t\t<Name>{esc_xml_text(child_name)}</Name>')
lines.append('\t\t\t<Synonym/>')
lines.append('\t\t\t<Comment/>')
lines.append('\t\t\t<IncludeHelpInContents>true</IncludeHelpInContents>')