Приводит все узлы Текст на полной глубине поддерева данного узла, включая узлы Атрибут, в "нормальную" форму, где только структуры (например, элементы, комментарии) разделяются текстовыми узлами, т.е. смежные текстовые узлы отсутствуют.
Синтаксис
Нормализовать()Полное описание, параметры и ограничения
ЭлементКартинкаHTML.Нормализовать (HTMLImageElement.Normalize)
ЭлементКартинкаHTML (HTMLImageElement)
Нормализовать (Normalize)
Доступен, начиная с версии 8.2.
Синтаксис:
Нормализовать()
Описание:
Приводит все узлы Текст на полной глубине поддерева данного узла, включая узлы Атрибут, в "нормальную" форму, где только структуры (например, элементы, комментарии) разделяются текстовыми узлами, т.е. смежные текстовые узлы отсутствуют.
Доступность:
Тонкий клиент, мобильный клиент, сервер, толстый клиент, внешнее соединение, мобильное приложение (клиент), мобильное приложение (сервер), мобильный автономный сервер.
Использование в версии:
Доступен, начиная с версии 8.2.
Методическая информация
Практические примеры
Нормализация атрибутов IMG и COL: два текста → один, код товара не меняется
Настоящие HTML узлы получаются из своей строки; реальные TextHTML клонируются в собственные атрибуты. Normalize меняет структуру 2 → 1, но A-01, исходные span и весь остальной логический DOM остаются прежними.
Где и как запускать
Только серверный неглобальный модуль собственной новой File CF 8.5.1.1343; толстая управляемая форма получает проверенные скаляры. Runtime не выполнялся.
Подготовка
Создайте вручную НОВУЮ пустую файловую учебную ИБ только C:\1c-labs\OwnHtmlAttribute2_6ad57c20-ec02-4501-a6b3-f52cb7f68219\IB. Конфигурация УчебнаяНормализацияHTML85; ОсновнойРежимЗапуска = УправляемоеПриложение; РежимСовместимости = НеИспользовать. Платформа Windows 8.5.1.1343, толстый управляемый клиент. Строка соединения должна быть точно File="этот полный путь"; без других параметров. UUID папки — маркер лаборатории, не доказательство идентичности базы.
Не добавляйте документы, справочники, регистры и расширения. Создайте свою роль HTML85Администратор с полными учебными правами, включая Администрирование и АктивныеПользователи. Создайте единственного пользователя HTML85Ученик и назначьте ему роль. Код проверяет настоящий UUID своего пользователя и единственное текущее соединение, но не создаёт пользователей и не меняет права.
Общие → Общие модули → HTMLНормализация85. Сервер = Да; Глобальный, ВызовСервера, Привилегированный, КлиентУправляемоеПриложение, КлиентОбычноеПриложение, ВнешнееСоединение = Нет. ПовторноеИспользованиеВозвращаемыхЗначений = НеИспользовать. Вставьте весь основной CODE. ВыполнитьНормализацию85 экспортируется без аргументов; все HTML объекты создаёт только этот код.
Общие → Общие формы → НормализацияАтрибутов85, управляемая форма. Добавьте семь реквизитов Число 15.2: Количество85, Цена85, Сумма85, ДоКартинки85, ПослеКартинки85, ДоКолонки85, ПослеКолонки85. Добавьте Код85 — Строка длина 20, Протокол85 — неограниченная Строка, Остановка85 и Завершено85 — Булево с начальным значением Ложь. Числа, код и многострочный протокол выводите только для просмотра; служебные Булево не показывайте.
Создайте собственную команду Нормализовать85, Действие = Нормализовать85(Команда), и кнопку командной панели, связанную с ней. Вставьте полный поддерживающий FORM. &НаСервере процедура вызывает свой серверный модуль; клиенту передаются только семь чисел и строка кода. HTML/DOM объекты, reader, атрибуты и снимки через RPC не передаются.
Конфигурация → Открыть модуль управляемого приложения: вставьте весь APPLICATION. Реальное ПриНачалеРаботыСистемы() без аргументов откроет свою форму только в толстом управляемом клиенте и после проверки собственного File/version/config marker. Не вызывайте startup и обработчик команды вручную.
Источник — только фиксированная короткая HTML строка этого урока: два своих span с A- и 01, img без src, col в colgroup и своя строка счёта A-01 / 3 / 250. HTML не отображается и не загружается в браузер. ЧтениеHTML и ПостроительDOM работают на сервере: builder не доступен в тонком клиенте, хотя сами HTML узлы там доступны. Свой reader закрывается в успехе и исключении.
Важно о factory. HTMLDocument.CreateTextNode3817 объявляет ТекстDOM, а HTMLAttribute.AppendChild принимает HTML union с ТекстHTML. Поэтому CreateTextNode не вызывается и XML текст не подставляется. Читаем реальные ТекстHTML из своих parsed span через HTMLNodeList.Item, проверяем все типы/значения/own document и клонируем именно их. Документированный CloneNode union включает ТекстHTML.
Новый AttrHTML берётся только из своего настоящего HTML документа. Его фактическая пустота и отстутствие владельца проверяются осторожно. Native OwnerElement объявляет ЭлементHTML, а не гарантированный Неопределено для нового узла: если getter бросит исключение или вернёт другое состояние, урок остановится и успех не будет заявлен. Начальные Count=0 и Value="" — проверяемое условие именно этого будущего стенда, не обещание конструктора.
IMG и COL — пустые теги. Детей им не добавляем. Два собственных TextHTML клона становятся детьми только своего атрибута data-study-code; его native Value формируется как A-01. Normalize на самом IMG/COL документированно включает атрибуты и объединяет соседние тексты: ожидаются 2 → 1 без изменения Value и без детей у элемента.
Перед каждой установкой атрибута и перед каждым Normalize перечитываем свой стенд, оба состояния атрибутов и весь логический DOM. Для полного сравнения делается отдельный deep clone текущего документа; из него удаляются только точно проверенные два собственных добавленных атрибута, после чего native УзелРавен сравнивает всю остальную логическую структуру с начальным deep snapshot. Удаляется только memory атрибут проверочной КОПИИ, никогда реальный атрибут рабочего учебного дерева. После проверки заново читаются оба реальных атрибута.
Обновите вручную только новую свою учебную CF, закройте Конфигуратор, запустите одного своего пользователя и нажмите команду один раз. После ошибки или успеха повтор в этой форме запрещён. Для нового ручного протокола закрывайте клиент, не сбрасывайте флаги в отладчике. Нет автоматического продолжения, retry, catch ремонта или восстановления.
Сейчас написан только source. 1С, CF, ИБ и GUI не создавались и не запускались. Нет сети, адресов картинок, файлового HTML, COM, записей ИБ и визуального рендеринга. Все числа и строка далее — ожидаемый будущий ручной протокол, не выполненный runtime.
Процедура ПроверитьСтенд85()
Если Метаданные.РежимСовместимости <> Метаданные.СвойстваОбъектов.РежимСовместимости.НеИспользовать Или СтрокаСоединенияИнформационнойБазы() <> "File=""C:\1c-labs\OwnHtmlAttribute2_6ad57c20-ec02-4501-a6b3-f52cb7f68219\IB"";" Тогда
ВызватьИсключение "Нужен только собственный точно подготовленный File стенд 8.5.1.1343";
КонецЕсли;
Если Метаданные.Документы.Количество() <> 0 Или Метаданные.Справочники.Количество() <> 0
Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0
Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0
Или Метаданные.ОбщиеМодули.Количество() <> 1 Или Метаданные.ОбщиеМодули.Найти("HTMLНормализация85") = Неопределено
Или Метаданные.ОбщиеФормы.Количество() <> 1 Или Метаданные.ОбщиеФормы.Найти("НормализацияАтрибутов85") = Неопределено Тогда
ВызватьИсключение "Оставьте только свой общий модуль и общую форму, без прикладных данных";
КонецЕсли;
МодульМД = Метаданные.ОбщиеМодули.Найти("HTMLНормализация85");
Если Не МодульМД.Сервер Или МодульМД.Глобальный Или МодульМД.ВызовСервера Или МодульМД.Привилегированный
Или МодульМД.КлиентУправляемоеПриложение Или МодульМД.КлиентОбычноеПриложение Или МодульМД.ВнешнееСоединение Тогда
ВызватьИсключение "Общий модуль должен быть только серверным и неглобальным";
КонецЕсли;
Если МодульМД.ПовторноеИспользованиеВозвращаемыхЗначений <> Метаданные.СвойстваОбъектов.ПовторноеИспользованиеВозвращаемыхЗначений.НеИспользовать Тогда
ВызватьИсключение "Запретите кеширование возвращаемых значений";
КонецЕсли;
Если РасширенияКонфигурации.Получить(, ИсточникРасширенийКонфигурации.БазаДанных).Количество() <> 0
Или РасширенияКонфигурации.Получить(, ИсточникРасширенийКонфигурации.СеансАктивные).Количество() <> 0
Или РасширенияКонфигурации.Получить(, ИсточникРасширенийКонфигурации.СеансОтключенные).Количество() <> 0 Тогда
ВызватьИсключение "В своей пустой лаборатории расширения не допускаются";
КонецЕсли;
Текущий = ПользователиИнформационнойБазы.ТекущийПользователь();
Пользователи = ПользователиИнформационнойБазы.ПолучитьПользователей();
Если Текущий = Неопределено Или Пользователи.Количество() <> 1 Тогда
ВызватьИсключение "Нужен один настоящий собственный пользователь";
КонецЕсли;
Если Текущий.Имя <> "HTML85Ученик" Или Пользователи[0].УникальныйИдентификатор <> Текущий.УникальныйИдентификатор Тогда
ВызватьИсключение "Не совпала настоящая идентичность учебного пользователя";
КонецЕсли;
Соединения = ПолучитьСоединенияИнформационнойБазы();
Если Соединения.Количество() <> 1 Тогда
ВызватьИсключение "Закройте Конфигуратор и другие сеансы своей лаборатории";
КонецЕсли;
Соединение = Соединения[0];
Если Соединение.НомерСоединения <> НомерСоединенияИнформационнойБазы()
Или Соединение.Пользователь.УникальныйИдентификатор <> Текущий.УникальныйИдентификатор Тогда
ВызватьИсключение "Единственное соединение должно принадлежать текущему своему пользователю";
КонецЕсли;
КонецПроцедуры
Функция ПрочитатьСвойHTML85()
HTML = "<html><head><title>Свой код товара</title></head><body><span id='prefix'>A-</span><span id='suffix'>01</span><img id='image' alt='Учебный товар'><table id='table'><colgroup id='group'><col id='column'></colgroup><tbody><tr id='row'><td id='code'>A-01</td><td id='quantity'>3</td><td id='price'>250</td></tr></tbody></table></body></html>";
Чтение = Новый ЧтениеHTML;
Чтение.УстановитьСтроку(HTML);
Попытка
Построитель = Новый ПостроительDOM;
Документ = Построитель.Прочитать(Чтение);
Исключение
Чтение.Закрыть();
ВызватьИсключение;
КонецПопытки;
Чтение.Закрыть();
Если ТипЗнч(Документ) <> Тип("ДокументHTML") Тогда
ВызватьИсключение "Свой HTML reader должен фактически дать ДокументHTML";
КонецЕсли;
Возврат Документ;
КонецФункции
Функция ПолучитьСвойУзел85(Документ, Идентификатор, ИмяТипа)
Если ТипЗнч(Документ) <> Тип("ДокументHTML") Тогда
ВызватьИсключение "Нужен настоящий собственный HTML документ";
КонецЕсли;
Узел = Документ.ПолучитьЭлементПоИдентификатору(Идентификатор);
Если Узел = Неопределено Тогда
ВызватьИсключение "В собственной подготовке не найден точный узел " + Идентификатор;
КонецЕсли;
Если ТипЗнч(Узел) <> Тип(ИмяТипа) Или Узел.ДокументВладелец <> Документ Тогда
ВызватьИсключение "Не совпали фактический специальный тип и собственный документ узла";
КонецЕсли;
Возврат Узел;
КонецФункции
Функция ПрочитатьСвойСчет85(Документ)
Код = ПолучитьСвойУзел85(Документ, "code", "ЭлементЯчейкаТаблицыHTML");
Количество = ПолучитьСвойУзел85(Документ, "quantity", "ЭлементЯчейкаТаблицыHTML");
Цена = ПолучитьСвойУзел85(Документ, "price", "ЭлементЯчейкаТаблицыHTML");
Если ТипЗнч(Код.ТекстовоеСодержимое) <> Тип("Строка") Или Код.ТекстовоеСодержимое <> "A-01"
Или ТипЗнч(Количество.ТекстовоеСодержимое) <> Тип("Строка") Или Количество.ТекстовоеСодержимое <> "3"
Или ТипЗнч(Цена.ТекстовоеСодержимое) <> Тип("Строка") Или Цена.ТекстовоеСодержимое <> "250" Тогда
ВызватьИсключение "Проверьте весь собственный код товара, количество и цену";
КонецЕсли;
ЧислоКоличества = Число(Количество.ТекстовоеСодержимое);
ЧислоЦены = Число(Цена.ТекстовоеСодержимое);
Сумма = ЧислоКоличества * ЧислоЦены;
Если ЧислоКоличества <> 3 Или ЧислоЦены <> 250 Или Сумма <> 750 Тогда
ВызватьИсключение "Не подтвердился настоящий расчет своего счета 3 x 250 = 750";
КонецЕсли;
Возврат Новый ФиксированнаяСтруктура("Количество,Цена,Сумма", ЧислоКоличества, ЧислоЦены, Сумма);
КонецФункции
Функция ПрочитатьСвойТекст85(Документ, Идентификатор, ОжидаемыйТекст)
Контейнер = ПолучитьСвойУзел85(Документ, Идентификатор, "ЭлементHTML");
Если Контейнер.ДочерниеУзлы.Количество() <> 1 Тогда
ВызватьИсключение "В своем span нужен ровно один реальный HTML текст";
КонецЕсли;
Текст = Контейнер.ДочерниеУзлы.Элемент(0);
Если ТипЗнч(Текст) <> Тип("ТекстHTML") Или Текст.ДокументВладелец <> Документ
Или ТипЗнч(Текст.ЗначениеУзла) <> Тип("Строка") Или Текст.ЗначениеУзла <> ОжидаемыйТекст Тогда
ВызватьИсключение "Не совпали настоящий HTML текст, его документ и вся исходная часть кода товара";
КонецЕсли;
Возврат Текст;
КонецФункции
Функция СоздатьСвоюМетку85(Документ)
Атрибут = Документ.СоздатьАтрибут("data-study-code");
Если ТипЗнч(Атрибут) <> Тип("АтрибутHTML") Или Атрибут.ДокументВладелец <> Документ
Или ТипЗнч(Атрибут.Имя) <> Тип("Строка") Или Атрибут.Имя <> "data-study-code"
Или ТипЗнч(Атрибут.Значение) <> Тип("Строка") Или Атрибут.Значение <> "" Или Атрибут.ДочерниеУзлы.Количество() <> 0 Тогда
ВызватьИсключение "Новый собственный атрибут допускается только после фактически подтвержденного пустого состояния";
КонецЕсли;
Если Атрибут.ЭлементВладелец <> Неопределено Тогда
ВызватьИсключение "Осторожная проверка своего нового атрибута не подтвердила отсутствие владельца";
КонецЕсли;
Префикс = ПрочитатьСвойТекст85(Документ, "prefix", "A-").КлонироватьУзел(Истина);
Суффикс = ПрочитатьСвойТекст85(Документ, "suffix", "01").КлонироватьУзел(Истина);
Если ТипЗнч(Префикс) <> Тип("ТекстHTML") Или ТипЗнч(Суффикс) <> Тип("ТекстHTML")
Или Префикс.ДокументВладелец <> Документ Или Суффикс.ДокументВладелец <> Документ
Или Префикс.РодительскийУзел <> Неопределено Или Суффикс.РодительскийУзел <> Неопределено
Или Префикс.ЗначениеУзла <> "A-" Или Суффикс.ЗначениеУзла <> "01" Тогда
ВызватьИсключение "Нужны два настоящих отсоединенных TextHTML клона этого же собственного документа";
КонецЕсли;
ДобавленПрефикс = Атрибут.ДобавитьДочерний(Префикс);
Если ТипЗнч(ДобавленПрефикс) <> Тип("ТекстHTML") Или Не ДобавленПрефикс.УзелИдентичен(Префикс)
Или Атрибут.ДочерниеУзлы.Количество() <> 1 Тогда
ВызватьИсключение "Не подтвержден реальный первый текст своего атрибута";
КонецЕсли;
ПервыйРебенок = Атрибут.ДочерниеУзлы.Элемент(0);
Если ТипЗнч(ПервыйРебенок) <> Тип("ТекстHTML") Или ПервыйРебенок.ДокументВладелец <> Документ
Или ПервыйРебенок.ЗначениеУзла <> "A-" Или Не ПервыйРебенок.УзелИдентичен(Префикс)
Или Атрибут.Значение <> "A-" Или Атрибут.ЭлементВладелец <> Неопределено Тогда
ВызватьИсключение "Перед вторым native Add перечитываем весь actual первый текст и свой еще отсоединенный атрибут";
КонецЕсли;
ДобавленСуффикс = Атрибут.ДобавитьДочерний(Суффикс);
Если ТипЗнч(ДобавленСуффикс) <> Тип("ТекстHTML") Или Не ДобавленСуффикс.УзелИдентичен(Суффикс) Или Атрибут.ДочерниеУзлы.Количество() <> 2
Или Атрибут.Значение <> "A-01" Тогда
ВызватьИсключение "Не подтверждены второй текст и native значение всего собственного атрибута";
КонецЕсли;
ПервыйРебенок = Атрибут.ДочерниеУзлы.Элемент(0);
ВторойРебенок = Атрибут.ДочерниеУзлы.Элемент(1);
Если ТипЗнч(ПервыйРебенок) <> Тип("ТекстHTML") Или ТипЗнч(ВторойРебенок) <> Тип("ТекстHTML")
Или ПервыйРебенок.ДокументВладелец <> Документ Или ВторойРебенок.ДокументВладелец <> Документ
Или ПервыйРебенок.ЗначениеУзла <> "A-" Или ВторойРебенок.ЗначениеУзла <> "01"
Или Не ПервыйРебенок.УзелИдентичен(Префикс) Или Не ВторойРебенок.УзелИдентичен(Суффикс)
Или Атрибут.ЭлементВладелец <> Неопределено Тогда
ВызватьИсключение "Весь staged атрибут должен остаться своим и содержать два точных HTML клона в нужном порядке";
КонецЕсли;
Возврат Атрибут;
КонецФункции
Функция ПроверитьМетку85(Элемент, Документ, НужныеДети)
Если ТипЗнч(Элемент) <> Тип("ЭлементКартинкаHTML") И ТипЗнч(Элемент) <> Тип("ЭлементКолонкаТаблицыHTML") Тогда
ВызватьИсключение "Допускаются только фактические свои img и col";
КонецЕсли;
Если Элемент.ДокументВладелец <> Документ Или Элемент.ДочерниеУзлы.Количество() <> 0 Или Элемент.ЕстьДочерниеУзлы() Тогда
ВызватьИсключение "Свой void элемент должен остаться в своем документе и без содержимого";
КонецЕсли;
Атрибут = Элемент.ПолучитьУзелАтрибута("data-study-code");
Если НужныеДети = 0 Тогда
Если Атрибут <> Неопределено Или Элемент.ЕстьАтрибут("data-study-code") Тогда
ВызватьИсключение "Свой новый атрибут уже присутствует; чужой или повторный результат не заменяем";
КонецЕсли;
Возврат Неопределено;
КонецЕсли;
Если НужныеДети <> 1 И НужныеДети <> 2 Тогда
ВызватьИсключение "Известны только два собственных этапа реальной структуры атрибута";
КонецЕсли;
Если ТипЗнч(Атрибут) <> Тип("АтрибутHTML") Или Атрибут.ДокументВладелец <> Документ
Или Атрибут.ЭлементВладелец <> Элемент Или Атрибут.Имя <> "data-study-code"
Или ТипЗнч(Атрибут.Значение) <> Тип("Строка") Или Атрибут.Значение <> "A-01"
Или Атрибут.ДочерниеУзлы.Количество() <> НужныеДети Тогда
ВызватьИсключение "Не совпало полное собственное описание атрибута";
КонецЕсли;
Для Индекс = 0 По НужныеДети - 1 Цикл
Текст = Атрибут.ДочерниеУзлы.Элемент(Индекс);
ОжидаемыйТекст = ?(НужныеДети = 1, "A-01", ?(Индекс = 0, "A-", "01"));
Если ТипЗнч(Текст) <> Тип("ТекстHTML") Или Текст.ДокументВладелец <> Документ
Или ТипЗнч(Текст.ЗначениеУзла) <> Тип("Строка") Или Текст.ЗначениеУзла <> ОжидаемыйТекст Тогда
ВызватьИсключение "Перечитайте все типы, значения и порядок собственных текстовых детей атрибута";
КонецЕсли;
КонецЦикла;
Возврат Атрибут;
КонецФункции
Процедура ПроверитьГраф85(Документ, Исходный, ДетиКартинки, ДетиКолонки)
ПроверитьСтенд85();
ПрочитатьСвойСчет85(Документ);
ПрочитатьСвойТекст85(Документ, "prefix", "A-");
ПрочитатьСвойТекст85(Документ, "suffix", "01");
Картинка = ПолучитьСвойУзел85(Документ, "image", "ЭлементКартинкаHTML");
Колонка = ПолучитьСвойУзел85(Документ, "column", "ЭлементКолонкаТаблицыHTML");
ПроверитьМетку85(Картинка, Документ, ДетиКартинки);
ПроверитьМетку85(Колонка, Документ, ДетиКолонки);
Если Картинка.ЕстьАтрибут("src") Тогда
ВызватьИсключение "Свой HTML не должен содержать источник внешней картинки";
КонецЕсли;
Копия = Документ.КлонироватьУзел(Истина);
Если ТипЗнч(Копия) <> Тип("ДокументHTML") Или Копия.УзелИдентичен(Документ) Тогда
ВызватьИсключение "Для сравнения целого дерева нужен фактический отдельный глубокий HTML клон";
КонецЕсли;
КартинкаКопии = ПолучитьСвойУзел85(Копия, "image", "ЭлементКартинкаHTML");
КолонкаКопии = ПолучитьСвойУзел85(Копия, "column", "ЭлементКолонкаТаблицыHTML");
МеткаКартинкиКопии = ПроверитьМетку85(КартинкаКопии, Копия, ДетиКартинки);
МеткаКолонкиКопии = ПроверитьМетку85(КолонкаКопии, Копия, ДетиКолонки);
Если ДетиКартинки > 0 Тогда
Удалена = КартинкаКопии.УдалитьУзелАтрибута(МеткаКартинкиКопии);
Если Не Удалена.УзелИдентичен(МеткаКартинкиКопии) Тогда
ВызватьИсключение "Удаляется только подтвержденный собственный атрибут отдельной проверочной копии";
КонецЕсли;
КонецЕсли;
Если ДетиКолонки > 0 Тогда
Удалена = КолонкаКопии.УдалитьУзелАтрибута(МеткаКолонкиКопии);
Если Не Удалена.УзелИдентичен(МеткаКолонкиКопии) Тогда
ВызватьИсключение "Удаляется только подтвержденный собственный атрибут отдельной проверочной копии";
КонецЕсли;
КонецЕсли;
ПроверитьМетку85(КартинкаКопии, Копия, 0);
ПроверитьМетку85(КолонкаКопии, Копия, 0);
Если ТипЗнч(Исходный) <> Тип("ДокументHTML") Или Не Копия.УзелРавен(Исходный) Тогда
ВызватьИсключение "Кроме двух точно разрешенных своих атрибутов изменилось целое логическое DOM дерево";
КонецЕсли;
ПроверитьМетку85(Картинка, Документ, ДетиКартинки);
ПроверитьМетку85(Колонка, Документ, ДетиКолонки);
КонецПроцедуры
Функция ВыполнитьНормализацию85() Экспорт
ПроверитьСтенд85();
Документ = ПрочитатьСвойHTML85();
Исходный = Документ.КлонироватьУзел(Истина);
Если ТипЗнч(Исходный) <> Тип("ДокументHTML") Или Исходный.УзелИдентичен(Документ) Или Не Исходный.УзелРавен(Документ) Тогда
ВызватьИсключение "До изменений нужен отдельный и полностью равный исходному логическому дереву deep snapshot";
КонецЕсли;
ПроверитьГраф85(Документ, Исходный, 0, 0);
Картинка = ПолучитьСвойУзел85(Документ, "image", "ЭлементКартинкаHTML");
Колонка = ПолучитьСвойУзел85(Документ, "column", "ЭлементКолонкаТаблицыHTML");
МеткаКартинки = СоздатьСвоюМетку85(Документ);
ПроверитьГраф85(Документ, Исходный, 0, 0);
Заменена = Картинка.УстановитьУзелАтрибута(МеткаКартинки);
Если Заменена <> Неопределено Тогда
ВызватьИсключение "При установке своего нового атрибута нельзя заменять уже существующий";
КонецЕсли;
ПроверитьГраф85(Документ, Исходный, 2, 0);
Если Не Картинка.ПолучитьУзелАтрибута("data-study-code").УзелИдентичен(МеткаКартинки) Тогда
ВызватьИсключение "До Normalize требуется идентичность реального прикрепленного атрибута картинки";
КонецЕсли;
МеткаКолонки = СоздатьСвоюМетку85(Документ);
ПроверитьГраф85(Документ, Исходный, 2, 0);
Заменена = Колонка.УстановитьУзелАтрибута(МеткаКолонки);
Если Заменена <> Неопределено Тогда
ВызватьИсключение "При установке своего нового атрибута нельзя заменять уже существующий";
КонецЕсли;
ПроверитьГраф85(Документ, Исходный, 2, 2);
Если Не Колонка.ПолучитьУзелАтрибута("data-study-code").УзелИдентичен(МеткаКолонки) Тогда
ВызватьИсключение "До Normalize требуется идентичность реального прикрепленного атрибута колонки";
КонецЕсли;
ДоКартинки = МеткаКартинки.ДочерниеУзлы.Количество();
ДоКолонки = МеткаКолонки.ДочерниеУзлы.Количество();
ПроверитьГраф85(Документ, Исходный, 2, 2);
Картинка.Нормализовать();
ПроверитьГраф85(Документ, Исходный, 1, 2);
Если Не Картинка.ПолучитьУзелАтрибута("data-study-code").УзелИдентичен(МеткаКартинки) Тогда
ВызватьИсключение "Normalize не должен подменить сам собственный атрибут картинки";
КонецЕсли;
ПослеКартинки = МеткаКартинки.ДочерниеУзлы.Количество();
ПроверитьГраф85(Документ, Исходный, 1, 2);
Колонка.Нормализовать();
ПроверитьГраф85(Документ, Исходный, 1, 1);
Если Не Колонка.ПолучитьУзелАтрибута("data-study-code").УзелИдентичен(МеткаКолонки) Тогда
ВызватьИсключение "Normalize не должен подменить сам собственный атрибут колонки";
КонецЕсли;
ПослеКолонки = МеткаКолонки.ДочерниеУзлы.Количество();
Если ДоКартинки <> 2 Или ДоКолонки <> 2 Или ПослеКартинки <> 1 Или ПослеКолонки <> 1
Или МеткаКартинки.Значение <> "A-01" Или МеткаКолонки.Значение <> "A-01" Тогда
ВызватьИсключение "Два native текстовых ребенка каждого атрибута должны стать одним без изменения кода товара";
КонецЕсли;
ПроверитьГраф85(Документ, Исходный, 1, 1);
Счет = ПрочитатьСвойСчет85(Документ);
Возврат Новый ФиксированнаяСтруктура("Количество,Цена,Сумма,ДоКартинки,ПослеКартинки,ДоКолонки,ПослеКолонки,Код",
Счет.Количество, Счет.Цена, Счет.Сумма, ДоКартинки, ПослеКартинки, ДоКолонки, ПослеКолонки, МеткаКартинки.Значение);
КонецФункцииСвоя команда формы, весь скалярный пакет и sticky STOP на двух границах
Общие → Общие формы → НормализацияАтрибутов85 → Модуль
Толстый управляемый клиент / &НаСервере
&НаКлиенте
Процедура Нормализовать85(Команда)
#Если ТолстыйКлиентУправляемоеПриложение Тогда
Если Остановка85 Или Завершено85 Или ТипЗнч(Команда) <> Тип("КомандаФормы") Или Команда <> Команды.Нормализовать85 Тогда
Остановка85 = Истина;
ВызватьИсключение "Допускается только своя команда и один запуск без повторения";
КонецЕсли;
Попытка
НормализоватьНаСервере85();
Если ТипЗнч(Количество85) <> Тип("Число") Или ТипЗнч(Цена85) <> Тип("Число") Или ТипЗнч(Сумма85) <> Тип("Число")
Или ТипЗнч(ДоКартинки85) <> Тип("Число") Или ТипЗнч(ПослеКартинки85) <> Тип("Число")
Или ТипЗнч(ДоКолонки85) <> Тип("Число") Или ТипЗнч(ПослеКолонки85) <> Тип("Число") Или ТипЗнч(Код85) <> Тип("Строка") Тогда
ВызватьИсключение "Клиент должен получить именно семь чисел и строку своего кода";
КонецЕсли;
Если Не Завершено85 Или Количество85 <> 3 Или Цена85 <> 250 Или Сумма85 <> 750
Или ДоКартинки85 <> 2 Или ПослеКартинки85 <> 1 Или ДоКолонки85 <> 2 Или ПослеКолонки85 <> 1 Или Код85 <> "A-01" Тогда
ВызватьИсключение "Не подтвержден весь собственный скалярный результат";
КонецЕсли;
Исключение
Остановка85 = Истина;
Протокол85 = "Отказ, не успех. Возможны только частичные memory изменения своего дерева. Повтор, восстановление и продолжение запрещены.";
ВызватьИсключение;
КонецПопытки;
#Иначе
Остановка85 = Истина;
ВызватьИсключение "Нужен свой толстый управляемый клиент";
#КонецЕсли
КонецПроцедуры
&НаСервере
Процедура НормализоватьНаСервере85()
Если Остановка85 Или Завершено85 Тогда
Остановка85 = Истина;
ВызватьИсключение "Серверная граница запрещает повтор после ошибки или успеха";
КонецЕсли;
Попытка
Пакет = HTMLНормализация85.ВыполнитьНормализацию85();
ПроверитьПакетНаСервере85(Пакет);
Если Пакет.Количество <> 3 Или Пакет.Цена <> 250 Или Пакет.Сумма <> 750
Или Пакет.ДоКартинки <> 2 Или Пакет.ПослеКартинки <> 1 Или Пакет.ДоКолонки <> 2
Или Пакет.ПослеКолонки <> 1 Или Пакет.Код <> "A-01" Тогда
ВызватьИсключение "Не принимайте частичный результат собственного примера";
КонецЕсли;
Количество85 = Пакет.Количество;
Цена85 = Пакет.Цена;
Сумма85 = Пакет.Сумма;
ДоКартинки85 = Пакет.ДоКартинки;
ПослеКартинки85 = Пакет.ПослеКартинки;
ДоКолонки85 = Пакет.ДоКолонки;
ПослеКолонки85 = Пакет.ПослеКолонки;
Код85 = Пакет.Код;
Протокол85 = "Код " + Код85 + ": атрибут картинки 2 → 1, атрибут колонки 2 → 1. Логические данные и весь остальной DOM сохранены. Свой счет 3 x 250 = 750. Рендеринг и сеть не проверялись.";
Завершено85 = Истина;
Исключение
Остановка85 = Истина;
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
&НаСервере
Процедура ПроверитьПакетНаСервере85(Пакет)
Если ТипЗнч(Пакет) <> Тип("ФиксированнаяСтруктура") Тогда
ВызватьИсключение "Перед чтением полей требуется реальная immutable ФиксированнаяСтруктура";
КонецЕсли;
Если Пакет.Количество() <> 8 Тогда
ВызватьИсключение "Не принимаем лишние или отсутствующие поля скалярного пакета";
КонецЕсли;
Для Каждого ИмяПоля Из СтрРазделить("Количество,Цена,Сумма,ДоКартинки,ПослеКартинки,ДоКолонки,ПослеКолонки", ",") Цикл
Если Не Пакет.Свойство(ИмяПоля, ЗначениеПоля) Или ТипЗнч(ЗначениеПоля) <> Тип("Число") Тогда
ВызватьИсключение "Каждое из семи точных своих полей должно существовать и содержать Число";
КонецЕсли;
КонецЦикла;
Если Не Пакет.Свойство("Код", ЗначениеПоля) Или ТипЗнч(ЗначениеПоля) <> Тип("Строка") Тогда
ВызватьИсключение "Восьмое точное поле должно быть реальной строкой своего кода";
КонецЕсли;
КонецПроцедурыРеальный startup открывает только свою учебную форму
Конфигурация → Открыть модуль управляемого приложения
Толстый управляемый клиент
Процедура ПриНачалеРаботыСистемы()
#Если ТолстыйКлиентУправляемоеПриложение Тогда
Если Метаданные.РежимСовместимости <> Метаданные.СвойстваОбъектов.РежимСовместимости.НеИспользовать Или СтрокаСоединенияИнформационнойБазы() <> "File=""C:\1c-labs\OwnHtmlAttribute2_6ad57c20-ec02-4501-a6b3-f52cb7f68219\IB"";" Тогда
ВызватьИсключение "Откройте только свою точно подготовленную новую учебную File базу";
КонецЕсли;
ОткрытьФорму("ОбщаяФорма.НормализацияАтрибутов85", , , Истина);
#Иначе
ВызватьИсключение "Нужен толстый управляемый клиент 8.5.1.1343";
#КонецЕсли
КонецПроцедурыРазбор по шагам
Проверяем точно свою File/version/configuration, server-only/no-cache module, отсутствие прикладных объектов и расширений, настоящего единственного пользователя и соединение. Собственный reader вместе с builder превращает фиксированную строку в actual ДокументHTML и закрывается в обеих ветках.
Начальный отдельный deep snapshot фактически равен всему своему документу. Получаем actual IMG/COL и два actual parsed ТекстHTML из своих span. Все операции включают проверку специального класса и того же own document; нового XML текста и фиктивных subtype конструкторов нет.
Каждый native AttrHTML создаётся в этом же документе и принимается только после фактически подтвержденного осторожного empty/detached guard. AppendChild добавляет два actual TextHTML клона A-/01. Значение A-01 получается из реальных детей, а не присваивается атрибуту или подставляется вместо результата.
У каждого IMG/COL перед SetAttributeNode подтверждается отсутствие data-study-code. Return Undefined означает, что старый атрибут не заменён; сразу перечитывается весь actual own граф с count2 и точными ordered TextHTML values. Самим void элементам дети не добавляются.
Свежая полная проверка 2/2 предшествует реальному Картинка.Нормализовать(); затем ожидается 1/2. Свежая проверка 1/2 предшествует Колонка.Нормализовать(); затем ожидается 1/1. Оба атрибута сохраняют свою идентичность, владельца и A-01; результат procedure не присваивается.
На каждой границе отдельный disposable deep clone без только двух exact own added атрибутов должен быть native равен всему initial DOM snapshot. Реальные атрибуты перечитываются после работы с копией. Свои ячейки дают фактический расчет 3×250=750; семь чисел и код целиком проверяются на сервере формы и на клиенте.
Как проверить результат
Будущий ручной протокол: ДоКартинки=2, ПослеКартинки=1, ДоКолонки=2, ПослеКолонки=1; оба native Value=A-01. Каждый оставшийся ребёнок actual ТекстHTML с полным A-01. IMG/COL по-прежнему имеют ноль детей; prefix=A-, suffix=01 и весь остальной логический DOM не изменены.
Количество=3, Цена=250, Сумма=750 вычислены из actual текста своих ячеек, а Код=A-01 читается из actual native атрибута. Незнакомый тип/документ/значение/порядок/count, уже существующий атрибут, непустое начальное состояние или изменившееся целое дерево означают отказ, не успешный учебный результат.
Кредитуются только две операции Normalize на своих конкретных IMG/COL. Остальные 11 исходных HTML leaf кандидатных API не добавлены: ни Compare с неизвестным return, ни child lifecycle void элементов, ни принудительный error-only вызов.
Ожидаемый результат
Ожидаемый будущий результат: A-01 / 3 / 250 / 750, атрибуты IMG и COL 2 → 1 каждый. Native фактически объединяет текстовые дети атрибутов, сохраняя их логическое значение. Это не выполненный здесь запуск 1С, не рендеринг и не браузерный DOM.
На что обратить внимание
SourceType CreateElement/GetElementById описан общим ЭлементHTML; это не обещание concrete типа. Поэтому actual IMG/COL всегда проверяются перед специальными операциями. Если платформа не даёт нужный класс, здесь нельзя объявить успех.
CreateTextNode3817 объявляет ТекстDOM и исключён. Клон берётся из настоящего parsed ТекстHTML; при другом фактическом type/owner/detached состоянии выполнение останавливается. Нельзя просто назвать произвольный XML узел HTML текстом.
Устанавливать Value для получения одного текста было бы другим действием: native Value setter удаляет всех детей и создаёт один. В этом уроке Value нигде не присваивается; actual count2 → count1 должен быть вызван именно Normalize на IMG/COL.
Отсутствие ElementOwner и empty children у нового AttrHTML не выдаются за гарантию справки. В частности OwnerElement документирован как ЭлементHTML. Осторожный guard может остановить будущую лабораторию; это неподтверждённый runtime, а не успешный результат через catch.
УзелРавен проверяет логические узлы, значения, атрибуты и порядок детей по native контракту; он не обещает побайтную сериализацию, равенство служебных пользовательских данных, DOM owner identity или визуальное совпадение. Identity собственных добавленных атрибутов проверяется отдельно.
Проверочная копия действительно отдельна от своего документа. Только из этой копии убираются два exact own атрибута для сравнения остальной структуры; живые атрибуты не удаляются и не восстанавливаются. Ошибка может оставить частичное memory состояние: sticky STOP запрещает повтор/слепой ремонт.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.