ЭлементБлокHTML.Нормализовать

Методы · Normalize

Приводит все узлы Текст на полной глубине поддерева данного узла, включая узлы Атрибут, в "нормальную" форму, где только структуры (например, элементы, комментарии) разделяются текстовыми узлами, т.е. смежные текстовые узлы отсутствуют.

Синтаксис

Нормализовать()
Полное описание, параметры и ограничения

ЭлементБлокHTML.Нормализовать (HTMLDivElement.Normalize)

ЭлементБлокHTML (HTMLDivElement)

Нормализовать (Normalize)

Доступен, начиная с версии 8.2.

Синтаксис:
Нормализовать()
Описание:

Приводит все узлы Текст на полной глубине поддерева данного узла, включая узлы Атрибут, в "нормальную" форму, где только структуры (например, элементы, комментарии) разделяются текстовыми узлами, т.е. смежные текстовые узлы отсутствуют.

Доступность:

Тонкий клиент, мобильный клиент, сервер, толстый клиент, внешнее соединение, мобильное приложение (клиент), мобильное приложение (сервер), мобильный автономный сервер.

Использование в версии:

Доступен, начиная с версии 8.2.

Методическая информация

Практические примеры

Вставить, заменить и удалить собственные служебные узлы контейнеров

В контейнерных элементах работаем с безопасными HTML-комментариями. Не добавляем детей в пустые теги input, img, col, meta, link, hr, frame и embed.

Где и как запускать

Учебная база: создайте серверный общий модуль УчебныеЗадачи (флаг Сервер). Код без директив вставьте в тело процедуры ВыполнитьПример() Экспорт. Вызовите её из серверного обработчика команды учебной обработки. Не запускайте в рабочей базе.

Подготовка

  1. Используйте учебную базу платформы 8.5.1.1343 и серверную процедуру учебного общего модуля. Каждый пример выполняйте отдельно.

  2. Все данные заказа вымышлены и находятся в строке. ЧтениеHTML разбирает данные, но не является браузером: форма не отправляется, ссылки не открываются, картинки не скачиваются.

  3. Никакие файлы, адреса сайтов, токены и документы информационной базы не нужны. Не заменяйте учебную строку произвольным внешним HTML без отдельной проверки безопасности.

  4. Индексы коллекций начинаются с нуля. Перед обращением к найденному узлу проверяйте Неопределено; перед специальными свойствами элемента проверяйте его тип.

HTML = "<html><head><title>Учебный заказ</title><meta id='meta' name='description' content='Вымышленный заказ'></head>
|<body id='body'><p id='note'>Заказ существует только в памяти</p><pre id='code'>A-01: 3
|B-02: 1</pre>
|<form id='order' name='order' action='' method='get'>
|<input id='customer' name='customer' type='text' value='Учебный покупатель'>
|<input id='accepted' name='accepted' type='checkbox' value='yes'>
|<button id='preview' name='preview' type='button' value='preview'>Предпросмотр</button></form>
|<table id='items' summary='Книга и ручка'><caption id='caption'>Товары</caption><colgroup><col id='column'></colgroup><tbody>
|<tr id='book'><td id='book-name'>Книга</td><td>3</td></tr><tr id='pen'><td>Ручка</td><td>1</td></tr>
|</tbody></table><a id='help' name='help' href='#note'>Пояснение</a><img id='logo' alt='Учебная картинка без источника'>
|</body></html>";
Чтение = Новый ЧтениеHTML;
Чтение.УстановитьСтроку(HTML);
Попытка
    Построитель = Новый ПостроительDOM;
    Документ = Построитель.Прочитать(Чтение);
Исключение
    Чтение.Закрыть();
    ВызватьИсключение;
КонецПопытки;
Чтение.Закрыть();
Если ТипЗнч(Документ) <> Тип("ДокументHTML") Тогда
    ВызватьИсключение "Ожидался ДокументHTML, а не XML-документ";
КонецЕсли;
Ожидаемые = Новый Соответствие;
Ожидаемые.Вставить("guide-section", "ЭлементHTML");
Ожидаемые.Вставить("div", "ЭлементБлокHTML");
Ожидаемые.Вставить("pre", "ЭлементФорматированногоТекстаHTML");
Ожидаемые.Вставить("form", "ЭлементФормаHTML");
Ожидаемые.Вставить("button", "ЭлементКнопкаHTML");
Ожидаемые.Вставить("table", "ЭлементТаблицаHTML");
Ожидаемые.Вставить("tr", "ЭлементСтрокаТаблицыHTML");
Ожидаемые.Вставить("td", "ЭлементЯчейкаТаблицыHTML");
Ожидаемые.Вставить("caption", "ЭлементЗаголовокТаблицыHTML");
Ожидаемые.Вставить("a", "ЭлементЯкорьHTML");
Ожидаемые.Вставить("head", "ЭлементЗаголовокHTML");
Ожидаемые.Вставить("html", "ЭлементРазметкаHTML");
Ожидаемые.Вставить("script", "ЭлементСкриптHTML");
Ожидаемые.Вставить("iframe", "ЭлементПлавающийФреймHTML");
Ожидаемые.Вставить("frameset", "ЭлементНаборФреймовHTML");
Ожидаемые.Вставить("object", "ЭлементОбъектHTML");
Ожидаемые.Вставить("applet", "ЭлементАплетHTML");
Для Каждого Пара Из Ожидаемые Цикл
    Узел = Документ.СоздатьЭлемент(Пара.Ключ);
    Если ТипЗнч(Узел) <> Тип(Пара.Значение) Тогда
        ВызватьИсключение "Фактический тип фабрики отличается для " + Пара.Ключ;
    КонецЕсли;
    Первый = Документ.СоздатьКомментарий("Урок A-01");
    Второй = Документ.СоздатьКомментарий("Проверка 3");
    НовыйУзел = Документ.СоздатьКомментарий("Проверка завершена");
    Узел.ДобавитьДочерний(Первый);
    Узел.ВставитьПеред(Второй, Первый);
    Сообщить(Узел.ПервыйДочерний = Второй);
    Узел.ЗаменитьДочерний(НовыйУзел, Первый);
    Сообщить(Узел.ПоследнийДочерний = НовыйУзел);
    Сообщить(Первый.РодительскийУзел = Неопределено);
    Узел.Нормализовать();
    Сообщить(Узел.ДочерниеУзлы.Количество() = 2);
    Удалённый = Узел.УдалитьДочерний(Второй);
    Сообщить(Удалённый = Второй);
    Узел.УдалитьДочерний(НовыйУзел);
    Сообщить(Не Узел.ЕстьДочерниеУзлы());
КонецЦикла;

Разбор по шагам

  1. Обрабатываем только 17 непустых по модели HTML тегов; элементы остаются вне документа заказа.

  2. ДобавитьДочерний вставляет первый служебный узел, ВставитьПеред добавляет второй перед ним.

  3. ЗаменитьДочерний вызывается без присваивания результата; прежний узел становится отсоединённым.

  4. Нормализовать не объединяет HTML-комментарии, затем удаляем два оставшихся узла.

Как проверить результат

  1. Шесть сравнений для каждого контейнера Истина; в конце у него снова нет детей.

  2. Комментарии не отображаются как текст заказа и не содержат исполняемого кода.

Ожидаемый результат

Показаны основные операции изменения дочернего дерева на конкретных контейнерных типах.

На что обратить внимание

  1. Не используйте текст комментария как скрытое хранилище секретов.

  2. Служебные комментарии не равны тегам товаров или новым строкам таблицы.

Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.

Граница нормализации HTML: лист сохраняет соседей, родитель объединяет тексты

На настоящих листовых ТекстHTML и КомментарийHTML своей строки проверить неизменность полного дерева после их Normalize. Затем показать контраст с уже покрытым DIV.Normalize: реальные соседние A-/01 превращаются в один A-01, а пометка и вычисленный счёт 750 сохраняются.

Где и как запускать

Сервер: собственный неглобальный непривилегированный HTMLГраница85; parser и все HTML/DOM объекты серверные. Клиент получает только строковый отчёт.

Подготовка

  1. Будущий ручной опыт: собственная НОВАЯ пустая учебная конфигурация на Windows, платформа 8.5.1.1343, управляемое приложение и толстый управляемый клиент. Не рабочая УТ, КА, УНФ или БП. HTML, reader, контрольная копия и расчёт создаются только в памяти одной функции без параметров; чужих объектов, файлов, URL и браузера нет.

  2. Общие → Общие модули → создать HTMLГраница85. Сервер=Да; Глобальный, Привилегированный, Вызов сервера, Клиент (управляемое приложение), Клиент (обычное приложение), Внешнее соединение=Нет. Повторное использование возвращаемых значений=Не использовать. Основной блок вставьте ЦЕЛИКОМ в пустой модуль; единственная экспортная функция Проверить85 не принимает входных объектов.

  3. Общие → Общие формы → создать управляемую ГраницаНормализацииHTML85. Один реквизит Результат85: Строка неограниченной длины. Выведите многострочное поле с ПутьКДанным=Результат85, ТолькоПросмотр=Да. Других данных, HTML-поля и событий автоматического запуска не требуется.

  4. В свойствах своей формы: АвтоматическоеСохранениеДанныхВНастройках=АвтоматическоеСохранениеДанныхФормыВНастройках.НеИспользовать; СохранениеДанныхВНастройках=СохранениеДанныхФормыВНастройках.НеИспользовать. Это два разных перечисления, не Булево.

  5. Создайте в форме команду Проверить85: Действие=Проверить85. Создайте кнопку и свяжите с этой командой. Поддерживающий модуль формы вставьте ЦЕЛИКОМ. Настоящий объект Команда передаёт платформа при нажатии; обработчик не вызывайте вручную.

  6. Общие → Общие команды → создать ОткрытьГраницуHTML85 без параметра, включить в командный интерфейс своей учебной подсистемы. Третий блок вставить ЦЕЛИКОМ в пустой модуль этой общей команды; &НаКлиенте задаёт настоящий контекст, а #Если проверяет вид клиентского приложения.

  7. После будущей проверки синтаксиса сохраните свою конфигурацию и обновите только её учебную базу. Откройте толстый управляемый клиент, своей общей командой откройте форму и нажмите Проверить85. Сервер возвращает только строку, не DOM-объекты. Этот запуск в 1С здесь не выполнялся.

  8. Для этой модели памяти не нужны отдельная 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");
    #Иначе
        ВызватьИсключение "Нужен толстый управляемый клиент";
    #КонецЕсли
КонецПроцедуры

Разбор по шагам

  1. Разбор строки — настоящий producer: ЧтениеHTML.УстановитьСтроку и ПостроительDOM.Прочитать. Для HTML reader native обещает ДокументHTML. ПолучитьЭлементПоИдентификатору обещает лишь общий ЭлементHTML либо Неопределено, поэтому каждый нужный DIV принимается только после фактического ЭлементБлокHTML и правильного документа-владельца.

  2. СписокУзловHTML.Элемент читается только после проверки количества. Так получаются настоящие ТекстHTML A-/01 и КомментарийHTML ORDER:A-01. Прямых конструкторов листьев и CreateTextNode/CreateComment нет: их DOM returns нельзя называть HTML returns.

  3. Два текста реально переносятся из собственных left/right в пустой code через ДобавитьДочерний у DIV. Возвращённые узлы, прежние пустые места, порядок и идентичность проверяются. Значения A-/01 не присваиваются новым фальшивым листьям.

  4. Глубокая отдельная копия всего подготовленного дерева должна сохранить два соседних текста и быть native равна рабочему документу, но не идентична ему. До двух листовых вызовов контрольная копия не нормализуется и не изменяется.

  5. Первый вызов — Левый85.Нормализовать() на реальном текстовом листе без детей и атрибутов. Его поддерево не включает родителя и соседний текст. После вызова заново читаются два прежних узла, их реальные данные/идентичность/владельцы, пометка и счёт; весь документ сравнивается с нетронутой глубокой копией.

  6. Второй вызов — Пометка85.Нормализовать() на настоящем листовом комментарии. Его данные и само место в note сохраняются; родитель code всё ещё содержит два текста. Полное повторное чтение и native равенство всего документа проверяются снова. Это полезный наблюдаемый no-op, не слияние детей комментария.

  7. Только теперь контраст: Нормализовать() у собственного code DIV. Fresh список содержит один настоящий ТекстHTML со всем A-01. Старые ссылки на два листа после слияния больше не разыменовываются: справка не обещает, какой из них останется.

  8. Нетронутая контрольная копия всё ещё имеет два текста. Только её собственный code DIV затем нормализуется до ожидаемого одного A-01. Native равенство всего рабочего документа с такой отдельной ожидаемой копией подтверждает, что остальная логическая структура не изменилась. Это не ремонт живого документа и не откат после ошибки.

  9. Реальные строки количества3/цены250 преобразуются в числа, их произведение750 проверяется и перечитывается на границах. Итоговый отчёт использует настоящие количества2/2/2/1, прочитанный A-01, сохранённую пометку и расчёт, не заранее записанные числа успеха.

Как проверить результат

  1. Будущий успешный опыт: текстовых узлов 2 → 2 после текстового листа → 2 после комментария → 1 после родителя. Код A-01, пометка ORDER:A-01, счёт 3 × 250 = 750 и контрольный текст НЕ МЕНЯТЬ сохраняются.

  2. В собственном учебном отладчике до и после двух листовых вызовов посмотрите реальные child counts0 и Атрибуты=Неопределено у листьев. В code должны оставаться оба прежних ТекстHTML с A-/01; native равенство всего документа с нетронутой отдельной копией должно быть Булево Истина.

  3. После вызова у родителя заново получите единственный ребёнок через список. Требуется actual ТекстHTML с Data A-01, а не назначенный заранее результат. Не проверяйте сохранение старой ссылки на второй лист.

  4. В отдельной собственной подготовке измените строку цены, пометку или контрольный текст. Ожидается прекращение проверки, а не подстановка750/старого успеха. Эти отрицательные случаи ещё не выполнялись в 1С; не объявляйте их измеренным результатом.

  5. При исключении форма показывает «Опыт НЕ завершён» и повторно вызывает ошибку. Для нового ручного опыта нажмите кнопку заново только после разбора причины: создастся новое дерево, не продолжение частичного старого состояния.

  6. Проверьте точные места вставки всех трёх полных модулей и два enum сохранения формы. Тонкий/веб-клиент не используется для producer: метод ПостроительDOM.Прочитать и Data legacy листьев имеют собственную ограниченную доступность.

  7. СравнитьПозициюВДокументе не вызывается: три native страницы не определяют возвращаемый контракт. W3C числа/маски здесь не подставляются; новые PRIMARY ровно два листовых Normalize.

Ожидаемый результат

Ожидаемый будущий ручной результат: реальные code числа детей 2 → 2 → 2 → 1, перечитанный код A-01, пометка ORDER:A-01, счёт3 × 250 = 750 и НЕ МЕНЯТЬ. Два листовых вызова являются наблюдаемым no-op на своём поддереве; слияние происходит только у родителя. Запуск в 1С пока не выполнен.

На что обратить внимание

  1. ТекстHTML и КомментарийHTML не рекомендуется использовать начиная с 8.2. Это ограниченный урок поддержки старого механизма 8.5.1.1343, а не новый браузерный интерфейс. Реальная parse shape и положительный путь ещё требуют ручного запуска; неподходящий тип/состав означает незавершённый опыт.

  2. Нормализовать имеет нулевую арность и применяется как statement: результат не присваивается. Сфера действия — поддерево данного receiver, включая его атрибуты; соседние узлы родителя туда не входят. Отсутствие изменения у подтверждённого листа не выдаётся за слияние или ошибку.

  3. Readonly ДочерниеУзлы/ДокументВладелец/Атрибуты не устанавливаются. Data и TextContent также нигде не присваиваются: родительское2→1 должно возникнуть именно через native Normalize. Attributes формально подписано коллекцией, но его native таблица явно задаёт Неопределено для Text/Comment; конкретный leaf count0 проверяется, не обещается для любого объекта.

  4. УзелРавен сравнивает логическую структуру, типы, значения, атрибуты и порядок/длину детей; не доказывает совпадение владельцев, родительских ссылок, пользовательских данных, сериализованных байтов или внешнего вида. Собственный owner и retained identities проверяются отдельно.

  5. Контрольная копия специально не нормализована до двух leaf-checks: иначе исчезнут два подготовленных соседних текста. Рекомендация нормализовать перед обычным сравнением здесь не используется, потому что предмет опыта — именно структура. Копия нормализуется отдельно только после обоих листовых опытов и настоящего родительского слияния.

  6. Reader.Close находится в обеих ветках, а SetString тоже внутри Попытка. Если Close сам выбросит исключение в ветке ошибки, он может скрыть первоначальную ошибку. Код честно останавливается; не обещает сохранение первоначальной причины, успешное закрытие или автоматическое восстановление.

  7. Никаких файлов, сети, HTML-рендеринга, запросов/записей БД, пользовательских профилей, печати и живого ремонта дерева. Статические проверки исходника/native contracts не являются компиляцией или выполнением1С.

  8. Формат Строка(Число) зависит от национальных установок; важны реальные числа и структура, а не побайтное совпадение текста отчёта. Имена/команды формы — учебные маршруты, не защита от подделки вызова.

Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.

Не хотите разбираться сами?

Адаптируем это решение под вашу базу. Оценка бесплатно.

Оставить задачу

1С, 1С:Предприятие — товарные знаки ООО «1С». Сайт не является официальным представительством фирмы «1С» и не аффилирован с ней.