Приводит все узлы Текст на полной глубине поддерева данного узла, включая узлы Атрибут, в "нормальную" форму, где только структуры (например, элементы, комментарии) разделяются текстовыми узлами, т.е. смежные текстовые узлы отсутствуют.
Синтаксис
Нормализовать()Полное описание, параметры и ограничения
ТекстHTML.Нормализовать (HTMLText.Normalize)
ТекстHTML (HTMLText)
Нормализовать (Normalize)
Доступен, начиная с версии 8.2.
Синтаксис:
Нормализовать()
Описание:
Приводит все узлы Текст на полной глубине поддерева данного узла, включая узлы Атрибут, в "нормальную" форму, где только структуры (например, элементы, комментарии) разделяются текстовыми узлами, т.е. смежные текстовые узлы отсутствуют.
Доступность:
Тонкий клиент, мобильный клиент, сервер, толстый клиент, внешнее соединение, мобильное приложение (клиент), мобильное приложение (сервер), мобильный автономный сервер.
Использование в версии:
Доступен, начиная с версии 8.2.
Методическая информация
Практические примеры
Граница нормализации HTML: лист сохраняет соседей, родитель объединяет тексты
На настоящих листовых ТекстHTML и КомментарийHTML своей строки проверить неизменность полного дерева после их Normalize. Затем показать контраст с уже покрытым DIV.Normalize: реальные соседние A-/01 превращаются в один A-01, а пометка и вычисленный счёт 750 сохраняются.
Где и как запускать
Сервер: собственный неглобальный непривилегированный HTMLГраница85; parser и все HTML/DOM объекты серверные. Клиент получает только строковый отчёт.
Подготовка
Будущий ручной опыт: собственная НОВАЯ пустая учебная конфигурация на Windows, платформа 8.5.1.1343, управляемое приложение и толстый управляемый клиент. Не рабочая УТ, КА, УНФ или БП. HTML, reader, контрольная копия и расчёт создаются только в памяти одной функции без параметров; чужих объектов, файлов, URL и браузера нет.
Общие → Общие модули → создать HTMLГраница85. Сервер=Да; Глобальный, Привилегированный, Вызов сервера, Клиент (управляемое приложение), Клиент (обычное приложение), Внешнее соединение=Нет. Повторное использование возвращаемых значений=Не использовать. Основной блок вставьте ЦЕЛИКОМ в пустой модуль; единственная экспортная функция Проверить85 не принимает входных объектов.
Общие → Общие формы → создать управляемую ГраницаНормализацииHTML85. Один реквизит Результат85: Строка неограниченной длины. Выведите многострочное поле с ПутьКДанным=Результат85, ТолькоПросмотр=Да. Других данных, HTML-поля и событий автоматического запуска не требуется.
В свойствах своей формы: АвтоматическоеСохранениеДанныхВНастройках=АвтоматическоеСохранениеДанныхФормыВНастройках.НеИспользовать; СохранениеДанныхВНастройках=СохранениеДанныхФормыВНастройках.НеИспользовать. Это два разных перечисления, не Булево.
Создайте в форме команду Проверить85: Действие=Проверить85. Создайте кнопку и свяжите с этой командой. Поддерживающий модуль формы вставьте ЦЕЛИКОМ. Настоящий объект Команда передаёт платформа при нажатии; обработчик не вызывайте вручную.
Общие → Общие команды → создать ОткрытьГраницуHTML85 без параметра, включить в командный интерфейс своей учебной подсистемы. Третий блок вставить ЦЕЛИКОМ в пустой модуль этой общей команды; &НаКлиенте задаёт настоящий контекст, а #Если проверяет вид клиентского приложения.
После будущей проверки синтаксиса сохраните свою конфигурацию и обновите только её учебную базу. Откройте толстый управляемый клиент, своей общей командой откройте форму и нажмите Проверить85. Сервер возвращает только строку, не DOM-объекты. Этот запуск в 1С здесь не выполнялся.
Для этой модели памяти не нужны отдельная VM, новый системный пользователь, UUID каталога или полный анализ метаданных. Новое нажатие создаёт новый собственный документ; ошибки предыдущего запуска не чинятся и не продолжаются, старая строка очищается перед обращением к серверу.
Функция ПрочитатьHTML85()
HTML85 = "<html><head><title>Граница нормализации</title></head><body><div id='left85'>A-</div><div id='right85'>01</div><div id='code85'></div><div id='note85'><!--ORDER:A-01--></div><div id='quantity85'>3</div><div id='price85'>250</div><div id='control85'>НЕ МЕНЯТЬ</div></body></html>";
Читатель85 = Новый ЧтениеHTML;
Попытка
Читатель85.УстановитьСтроку(HTML85);
Построитель85 = Новый ПостроительDOM;
Документ85 = Построитель85.Прочитать(Читатель85);
Исключение
Читатель85.Закрыть();
ВызватьИсключение;
КонецПопытки;
Читатель85.Закрыть();
Если ТипЗнч(Документ85) <> Тип("ДокументHTML") Тогда
ВызватьИсключение "Собственная строка не дала настоящий ДокументHTML";
КонецЕсли;
Возврат Документ85;
КонецФункции
Функция ПолучитьБлок85(Документ85, Идентификатор85)
Блок85 = Документ85.ПолучитьЭлементПоИдентификатору(Идентификатор85);
Если ТипЗнч(Блок85) <> Тип("ЭлементБлокHTML") Или Блок85.ДокументВладелец <> Документ85 Тогда
ВызватьИсключение "Не найден нужный собственный DIV этого документа";
КонецЕсли;
Возврат Блок85;
КонецФункции
Процедура ПроверитьТекст85(Текст85, Документ85, Данные85)
Если ТипЗнч(Текст85) <> Тип("ТекстHTML") Или Текст85.ДокументВладелец <> Документ85
Или ТипЗнч(Текст85.Данные) <> Тип("Строка") Или Текст85.Данные <> Данные85
Или Текст85.ДочерниеУзлы.Количество() <> 0 Или Текст85.Атрибуты <> Неопределено Тогда
ВызватьИсключение "Нужен настоящий собственный текстовый лист с точными данными";
КонецЕсли;
КонецПроцедуры
Функция ПрочитатьОдинТекст85(Документ85, Идентификатор85, Данные85)
Список85 = ПолучитьБлок85(Документ85, Идентификатор85).ДочерниеУзлы;
Количество85 = Список85.Количество();
Если ТипЗнч(Список85) <> Тип("СписокУзловHTML") Или ТипЗнч(Количество85) <> Тип("Число") Или Количество85 <> 1 Тогда
ВызватьИсключение "В своём блоке ожидается ровно один реальный текст";
КонецЕсли;
Текст85 = Список85.Элемент(0);
ПроверитьТекст85(Текст85, Документ85, Данные85);
Возврат Текст85;
КонецФункции
Функция ПроверитьДваТекста85(Документ85, Левый85, Правый85, ДанныеЛевого85, ДанныеПравого85)
Если ПолучитьБлок85(Документ85, "left85").ДочерниеУзлы.Количество() <> 0
Или ПолучитьБлок85(Документ85, "right85").ДочерниеУзлы.Количество() <> 0 Тогда
ВызватьИсключение "Оба исходных текста должны быть перенесены из своих прежних блоков";
КонецЕсли;
Список85 = ПолучитьБлок85(Документ85, "code85").ДочерниеУзлы;
Количество85 = Список85.Количество();
Если ТипЗнч(Список85) <> Тип("СписокУзловHTML") Или ТипЗнч(Количество85) <> Тип("Число") Или Количество85 <> 2 Тогда
ВызватьИсключение "У собственного родителя должны остаться два текста, а не один";
КонецЕсли;
Первый85 = Список85.Элемент(0);
Второй85 = Список85.Элемент(1);
ПроверитьТекст85(Первый85, Документ85, ДанныеЛевого85);
ПроверитьТекст85(Второй85, Документ85, ДанныеПравого85);
ТотЖеПервый85 = Первый85.УзелИдентичен(Левый85);
ТотЖеВторой85 = Второй85.УзелИдентичен(Правый85);
Если ТипЗнч(ТотЖеПервый85) <> Тип("Булево") Или Не ТотЖеПервый85
Или ТипЗнч(ТотЖеВторой85) <> Тип("Булево") Или Не ТотЖеВторой85 Тогда
ВызватьИсключение "Порядок и настоящая идентичность обоих собственных листьев изменились";
КонецЕсли;
Блок85 = ПолучитьБлок85(Документ85, "code85");
Если ТипЗнч(Блок85.ТекстовоеСодержимое) <> Тип("Строка")
Или Блок85.ТекстовоеСодержимое <> ДанныеЛевого85 + ДанныеПравого85 Тогда
ВызватьИсключение "Полное текстовое значение собственного родителя изменилось";
КонецЕсли;
Возврат Количество85;
КонецФункции
Функция ПроверитьПометку85(Документ85, Пометка85, ДанныеПометки85)
Список85 = ПолучитьБлок85(Документ85, "note85").ДочерниеУзлы;
Если ТипЗнч(Список85) <> Тип("СписокУзловHTML") Или Список85.Количество() <> 1 Тогда
ВызватьИсключение "Ожидается одна собственная техническая пометка";
КонецЕсли;
ПрочитаннаяПометка85 = Список85.Элемент(0);
Если ТипЗнч(ПрочитаннаяПометка85) <> Тип("КомментарийHTML")
Или ПрочитаннаяПометка85.ДокументВладелец <> Документ85
Или ТипЗнч(ПрочитаннаяПометка85.Данные) <> Тип("Строка")
Или ПрочитаннаяПометка85.Данные <> ДанныеПометки85
Или ПрочитаннаяПометка85.ДочерниеУзлы.Количество() <> 0
Или ПрочитаннаяПометка85.Атрибуты <> Неопределено Тогда
ВызватьИсключение "Собственная пометка перестала быть точным листовым комментарием";
КонецЕсли;
ТаЖеПометка85 = ПрочитаннаяПометка85.УзелИдентичен(Пометка85);
Если ТипЗнч(ТаЖеПометка85) <> Тип("Булево") Или Не ТаЖеПометка85 Тогда
ВызватьИсключение "Вместо прежней собственной пометки оказался другой узел";
КонецЕсли;
Возврат ПрочитаннаяПометка85.Данные;
КонецФункции
Функция ПрочитатьСчёт85(Документ85)
ТекстКоличества85 = ПрочитатьОдинТекст85(Документ85, "quantity85", "3");
ТекстЦены85 = ПрочитатьОдинТекст85(Документ85, "price85", "250");
Контроль85 = ПрочитатьОдинТекст85(Документ85, "control85", "НЕ МЕНЯТЬ");
Количество85 = Число(ТекстКоличества85.Данные);
Цена85 = Число(ТекстЦены85.Данные);
Сумма85 = Количество85 * Цена85;
Если ТипЗнч(Количество85) <> Тип("Число") Или Количество85 <> 3
Или ТипЗнч(Цена85) <> Тип("Число") Или Цена85 <> 250 Или Сумма85 <> 750 Тогда
ВызватьИсключение "Реальные данные своего счёта не подтвердили 3 × 250 = 750";
КонецЕсли;
Возврат Строка(Количество85) + " × " + Строка(Цена85) + " = " + Строка(Сумма85) + "; " + Контроль85.Данные;
КонецФункции
Процедура ПроверитьРавенство85(Документ85, Копия85)
Равен85 = Документ85.УзелРавен(Копия85);
Если ТипЗнч(Равен85) <> Тип("Булево") Или Не Равен85 Тогда
ВызватьИсключение "Изменилось полное логическое дерево, а не только разрешённая структура";
КонецЕсли;
КонецПроцедуры
Функция Проверить85() Экспорт
Документ85 = ПрочитатьHTML85();
Левый85 = ПрочитатьОдинТекст85(Документ85, "left85", "A-");
Правый85 = ПрочитатьОдинТекст85(Документ85, "right85", "01");
ДанныеЛевого85 = Левый85.Данные;
ДанныеПравого85 = Правый85.Данные;
Код85 = ДанныеЛевого85 + ДанныеПравого85;
СписокПометок85 = ПолучитьБлок85(Документ85, "note85").ДочерниеУзлы;
Если ТипЗнч(СписокПометок85) <> Тип("СписокУзловHTML") Или СписокПометок85.Количество() <> 1 Тогда
ВызватьИсключение "Своя пометка не подготовлена";
КонецЕсли;
Пометка85 = СписокПометок85.Элемент(0);
Если ТипЗнч(Пометка85) <> Тип("КомментарийHTML") Тогда
ВызватьИсключение "Нужен КомментарийHTML из собственной разобранной строки, не новый XML-комментарий";
КонецЕсли;
ПометкаДо85 = ПроверитьПометку85(Документ85, Пометка85, "ORDER:" + Код85);
СчётДо85 = ПрочитатьСчёт85(Документ85);
КодовыйБлок85 = ПолучитьБлок85(Документ85, "code85");
Если КодовыйБлок85.ДочерниеУзлы.Количество() <> 0 Тогда
ВызватьИсключение "Свой кодовый блок должен начинаться пустым";
КонецЕсли;
ДобавленЛевый85 = КодовыйБлок85.ДобавитьДочерний(Левый85);
Если ТипЗнч(ДобавленЛевый85) <> Тип("ТекстHTML") Или Не ДобавленЛевый85.УзелИдентичен(Левый85)
Или ПолучитьБлок85(Документ85, "left85").ДочерниеУзлы.Количество() <> 0
Или КодовыйБлок85.ДочерниеУзлы.Количество() <> 1 Тогда
ВызватьИсключение "Первый собственный текст не перенесён";
КонецЕсли;
ДобавленПравый85 = КодовыйБлок85.ДобавитьДочерний(Правый85);
Если ТипЗнч(ДобавленПравый85) <> Тип("ТекстHTML") Или Не ДобавленПравый85.УзелИдентичен(Правый85) Тогда
ВызватьИсключение "Второй собственный текст не перенесён";
КонецЕсли;
До85 = ПроверитьДваТекста85(Документ85, Левый85, Правый85, ДанныеЛевого85, ДанныеПравого85);
Копия85 = Документ85.КлонироватьУзел(Истина);
Если ТипЗнч(Копия85) <> Тип("ДокументHTML") Тогда
ВызватьИсключение "Для полного контроля нужна настоящая глубокая копия ДокументHTML";
КонецЕсли;
ТаЖеКопия85 = Копия85.УзелИдентичен(Документ85);
Если ТипЗнч(ТаЖеКопия85) <> Тип("Булево") Или ТаЖеКопия85 Тогда
ВызватьИсключение "Контрольная копия не должна ссылаться на рабочий документ";
КонецЕсли;
ПроверитьРавенство85(Документ85, Копия85);
Если ПолучитьБлок85(Копия85, "code85").ДочерниеУзлы.Количество() <> 2 Тогда
ВызватьИсключение "Глубокая копия должна сохранить именно два соседних текста";
КонецЕсли;
Левый85.Нормализовать();
ПослеТекста85 = ПроверитьДваТекста85(Документ85, Левый85, Правый85, ДанныеЛевого85, ДанныеПравого85);
Если ПроверитьПометку85(Документ85, Пометка85, ПометкаДо85) <> ПометкаДо85
Или ПрочитатьСчёт85(Документ85) <> СчётДо85 Тогда
ВызватьИсключение "Листовая нормализация текста изменила свою пометку или счёт";
КонецЕсли;
ПроверитьРавенство85(Документ85, Копия85);
Пометка85.Нормализовать();
ПослеПометки85 = ПроверитьДваТекста85(Документ85, Левый85, Правый85, ДанныеЛевого85, ДанныеПравого85);
Если ПроверитьПометку85(Документ85, Пометка85, ПометкаДо85) <> ПометкаДо85
Или ПрочитатьСчёт85(Документ85) <> СчётДо85 Тогда
ВызватьИсключение "Листовая нормализация комментария изменила свои данные";
КонецЕсли;
ПроверитьРавенство85(Документ85, Копия85);
КодовыйБлок85 = ПолучитьБлок85(Документ85, "code85");
КодовыйБлок85.Нормализовать();
КонечныйТекст85 = ПрочитатьОдинТекст85(Документ85, "code85", Код85);
ПослеРодителя85 = КодовыйБлок85.ДочерниеУзлы.Количество();
КодПосле85 = КодовыйБлок85.ТекстовоеСодержимое;
Если ТипЗнч(КодПосле85) <> Тип("Строка") Или КодПосле85 <> КонечныйТекст85.Данные Тогда
ВызватьИсключение "Перечитанный целый код не совпал с настоящим объединённым текстом";
КонецЕсли;
БлокКопии85 = ПолучитьБлок85(Копия85, "code85");
Если БлокКопии85.ДочерниеУзлы.Количество() <> 2 Тогда
ВызватьИсключение "Нетронутая контрольная копия неожиданно изменилась";
КонецЕсли;
БлокКопии85.Нормализовать();
ТекстКопии85 = ПрочитатьОдинТекст85(Копия85, "code85", Код85);
Если ТекстКопии85.Данные <> КонечныйТекст85.Данные Тогда
ВызватьИсключение "В реальной и ожидаемой структуре не совпал код";
КонецЕсли;
ПроверитьРавенство85(Документ85, Копия85);
ПометкаПосле85 = ПроверитьПометку85(Документ85, Пометка85, ПометкаДо85);
СчётПосле85 = ПрочитатьСчёт85(Документ85);
Если ТипЗнч(ПослеРодителя85) <> Тип("Число") Или ПослеРодителя85 <> 1
Или ПометкаПосле85 <> ПометкаДо85 Или СчётПосле85 <> СчётДо85
Или ПолучитьБлок85(Документ85, "left85").ДочерниеУзлы.Количество() <> 0
Или ПолучитьБлок85(Документ85, "right85").ДочерниеУзлы.Количество() <> 0 Тогда
ВызватьИсключение "Полный итоговый контроль собственного документа не пройден";
КонецЕсли;
Возврат "Текстовых узлов: " + Строка(До85) + " → " + Строка(ПослеТекста85)
+ " → " + Строка(ПослеПометки85) + " → " + Строка(ПослеРодителя85)
+ ". Код: " + КодПосле85 + ". Пометка: " + ПометкаПосле85 + ". Счёт: " + СчётПосле85;
КонецФункцииПолный модуль собственной формы ГраницаНормализацииHTML85
Общие → Общие формы → ГраницаНормализацииHTML85 → пустой модуль формы. Вставить ЦЕЛИКОМ; своя команда Проверить85 связана через Действие.
Реальная команда формы &НаКлиенте; обращение к своему общему модулю &НаСервере. Передаётся только Строка.
&НаКлиенте
Процедура Проверить85(Команда)
Если ТипЗнч(Команда) <> Тип("КомандаФормы") Или Команда.Имя <> "Проверить85" Тогда
ВызватьИсключение "Нужна настоящая собственная команда формы";
КонецЕсли;
Результат85 = "";
Попытка
Получено85 = ПроверитьНаСервере85();
Если ТипЗнч(Получено85) <> Тип("Строка") Или Получено85 = "" Тогда
ВызватьИсключение "Сервер не вернул полный строковый отчёт";
КонецЕсли;
Результат85 = Получено85;
Исключение
Результат85 = "Опыт НЕ завершён. Данные и структура не подтверждены.";
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
&НаСервере
Функция ПроверитьНаСервере85()
Если ИмяФормы <> "ОбщаяФорма.ГраницаНормализацииHTML85"
Или АвтоматическоеСохранениеДанныхВНастройках <> АвтоматическоеСохранениеДанныхФормыВНастройках.НеИспользовать
Или СохранениеДанныхВНастройках <> СохранениеДанныхФормыВНастройках.НеИспользовать Тогда
ВызватьИсключение "Нужна своя форма с отключённым сохранением данных";
КонецЕсли;
Отчёт85 = HTMLГраница85.Проверить85();
Если ТипЗнч(Отчёт85) <> Тип("Строка") Или Отчёт85 = "" Тогда
ВызватьИсключение "Не получен полный строковый результат своего серверного модуля";
КонецЕсли;
Возврат Отчёт85;
КонецФункцииПолный модуль собственной общей команды ОткрытьГраницуHTML85
Общие → Общие команды → ОткрытьГраницуHTML85 → пустой модуль команды. Вставить ЦЕЛИКОМ, включить без параметра в свой учебный интерфейс.
&НаКлиенте; толстый управляемый клиент, настоящее ОбработкаКоманды с двумя штатными параметрами.
&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
#Если ТолстыйКлиентУправляемоеПриложение Тогда
Если ПараметрКоманды <> Неопределено
Или ТипЗнч(ПараметрыВыполненияКоманды) <> Тип("ПараметрыВыполненияКоманды") Тогда
ВызватьИсключение "Откройте собственную форму штатной общей командой без параметра";
КонецЕсли;
ОткрытьФорму("ОбщаяФорма.ГраницаНормализацииHTML85");
#Иначе
ВызватьИсключение "Нужен толстый управляемый клиент";
#КонецЕсли
КонецПроцедурыРазбор по шагам
Разбор строки — настоящий producer: ЧтениеHTML.УстановитьСтроку и ПостроительDOM.Прочитать. Для HTML reader native обещает ДокументHTML. ПолучитьЭлементПоИдентификатору обещает лишь общий ЭлементHTML либо Неопределено, поэтому каждый нужный DIV принимается только после фактического ЭлементБлокHTML и правильного документа-владельца.
СписокУзловHTML.Элемент читается только после проверки количества. Так получаются настоящие ТекстHTML A-/01 и КомментарийHTML ORDER:A-01. Прямых конструкторов листьев и CreateTextNode/CreateComment нет: их DOM returns нельзя называть HTML returns.
Два текста реально переносятся из собственных left/right в пустой code через ДобавитьДочерний у DIV. Возвращённые узлы, прежние пустые места, порядок и идентичность проверяются. Значения A-/01 не присваиваются новым фальшивым листьям.
Глубокая отдельная копия всего подготовленного дерева должна сохранить два соседних текста и быть native равна рабочему документу, но не идентична ему. До двух листовых вызовов контрольная копия не нормализуется и не изменяется.
Первый вызов — Левый85.Нормализовать() на реальном текстовом листе без детей и атрибутов. Его поддерево не включает родителя и соседний текст. После вызова заново читаются два прежних узла, их реальные данные/идентичность/владельцы, пометка и счёт; весь документ сравнивается с нетронутой глубокой копией.
Второй вызов — Пометка85.Нормализовать() на настоящем листовом комментарии. Его данные и само место в note сохраняются; родитель code всё ещё содержит два текста. Полное повторное чтение и native равенство всего документа проверяются снова. Это полезный наблюдаемый no-op, не слияние детей комментария.
Только теперь контраст: Нормализовать() у собственного code DIV. Fresh список содержит один настоящий ТекстHTML со всем A-01. Старые ссылки на два листа после слияния больше не разыменовываются: справка не обещает, какой из них останется.
Нетронутая контрольная копия всё ещё имеет два текста. Только её собственный code DIV затем нормализуется до ожидаемого одного A-01. Native равенство всего рабочего документа с такой отдельной ожидаемой копией подтверждает, что остальная логическая структура не изменилась. Это не ремонт живого документа и не откат после ошибки.
Реальные строки количества3/цены250 преобразуются в числа, их произведение750 проверяется и перечитывается на границах. Итоговый отчёт использует настоящие количества2/2/2/1, прочитанный A-01, сохранённую пометку и расчёт, не заранее записанные числа успеха.
Как проверить результат
Будущий успешный опыт: текстовых узлов 2 → 2 после текстового листа → 2 после комментария → 1 после родителя. Код A-01, пометка ORDER:A-01, счёт 3 × 250 = 750 и контрольный текст НЕ МЕНЯТЬ сохраняются.
В собственном учебном отладчике до и после двух листовых вызовов посмотрите реальные child counts0 и Атрибуты=Неопределено у листьев. В code должны оставаться оба прежних ТекстHTML с A-/01; native равенство всего документа с нетронутой отдельной копией должно быть Булево Истина.
После вызова у родителя заново получите единственный ребёнок через список. Требуется actual ТекстHTML с Data A-01, а не назначенный заранее результат. Не проверяйте сохранение старой ссылки на второй лист.
В отдельной собственной подготовке измените строку цены, пометку или контрольный текст. Ожидается прекращение проверки, а не подстановка750/старого успеха. Эти отрицательные случаи ещё не выполнялись в 1С; не объявляйте их измеренным результатом.
При исключении форма показывает «Опыт НЕ завершён» и повторно вызывает ошибку. Для нового ручного опыта нажмите кнопку заново только после разбора причины: создастся новое дерево, не продолжение частичного старого состояния.
Проверьте точные места вставки всех трёх полных модулей и два enum сохранения формы. Тонкий/веб-клиент не используется для producer: метод ПостроительDOM.Прочитать и Data legacy листьев имеют собственную ограниченную доступность.
СравнитьПозициюВДокументе не вызывается: три native страницы не определяют возвращаемый контракт. W3C числа/маски здесь не подставляются; новые PRIMARY ровно два листовых Normalize.
Ожидаемый результат
Ожидаемый будущий ручной результат: реальные code числа детей 2 → 2 → 2 → 1, перечитанный код A-01, пометка ORDER:A-01, счёт3 × 250 = 750 и НЕ МЕНЯТЬ. Два листовых вызова являются наблюдаемым no-op на своём поддереве; слияние происходит только у родителя. Запуск в 1С пока не выполнен.
На что обратить внимание
ТекстHTML и КомментарийHTML не рекомендуется использовать начиная с 8.2. Это ограниченный урок поддержки старого механизма 8.5.1.1343, а не новый браузерный интерфейс. Реальная parse shape и положительный путь ещё требуют ручного запуска; неподходящий тип/состав означает незавершённый опыт.
Нормализовать имеет нулевую арность и применяется как statement: результат не присваивается. Сфера действия — поддерево данного receiver, включая его атрибуты; соседние узлы родителя туда не входят. Отсутствие изменения у подтверждённого листа не выдаётся за слияние или ошибку.
Readonly ДочерниеУзлы/ДокументВладелец/Атрибуты не устанавливаются. Data и TextContent также нигде не присваиваются: родительское2→1 должно возникнуть именно через native Normalize. Attributes формально подписано коллекцией, но его native таблица явно задаёт Неопределено для Text/Comment; конкретный leaf count0 проверяется, не обещается для любого объекта.
УзелРавен сравнивает логическую структуру, типы, значения, атрибуты и порядок/длину детей; не доказывает совпадение владельцев, родительских ссылок, пользовательских данных, сериализованных байтов или внешнего вида. Собственный owner и retained identities проверяются отдельно.
Контрольная копия специально не нормализована до двух leaf-checks: иначе исчезнут два подготовленных соседних текста. Рекомендация нормализовать перед обычным сравнением здесь не используется, потому что предмет опыта — именно структура. Копия нормализуется отдельно только после обоих листовых опытов и настоящего родительского слияния.
Reader.Close находится в обеих ветках, а SetString тоже внутри Попытка. Если Close сам выбросит исключение в ветке ошибки, он может скрыть первоначальную ошибку. Код честно останавливается; не обещает сохранение первоначальной причины, успешное закрытие или автоматическое восстановление.
Никаких файлов, сети, HTML-рендеринга, запросов/записей БД, пользовательских профилей, печати и живого ремонта дерева. Статические проверки исходника/native contracts не являются компиляцией или выполнением1С.
Формат Строка(Число) зависит от национальных установок; важны реальные числа и структура, а не побайтное совпадение текста отчёта. Имена/команды формы — учебные маршруты, не защита от подделки вызова.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.