Работа с XML-документами через объектную модель DOM (Document Object Model) в 1С — это мощный инструмент, позволяющий гибко изменять структуру файла, добавлять новые узлы и редактировать атрибуты. Однако начинающие разработчики часто сталкиваются с проблемой при попытке добавить элемент в коллекцию СписокЭлементовDOM. В этой статье мы подробно разберем, почему нельзя добавить элемент напрямую в список и как правильно модифицировать дерево документа.
Рассмотрим ситуацию: мы прочитали XML-документ, нашли группу нужных нам тегов и хотим добавить туда новый узел. Типичная ошибка — пытаться вызвать метод Добавить() или Вставить() непосредственно у объекта СписокЭлементовDOM. Проанализируем причину, по которой это невозможно.
Объект СписокЭлементовDOM (в других языках программирования известный как NodeList) является итерируемой коллекцией, которая представляет собой результат поискового запроса (например, после вызова метода ПолучитьЭлементыПоИмени). Этот список предназначен только для чтения и отражает текущее состояние дерева документа. Чтобы новый элемент «появился» в этом списке, его нужно добавить физически в дерево DOM к конкретному родительскому узлу.
Для того чтобы добавить новый элемент в структуру, нам необходимо выполнить последовательность действий. Разберем этот процесс по шагам.
ПолучитьЭлементыПоИмени или поиск по XPath.[0]).СоздатьЭлемент.ДобавитьДочерний у выбранного ранее узла.Проанализируем пример кода, в котором мы ищем родительский узел и добавляем в него новые данные:
// 1. Создаем построитель и читаем XML
ОбъектXML = Новый ЧтениеXML;
ОбъектXML.УстановитьСтроку(Вложение.XMLДокумента);
ПостроительDOM = Новый ПостроительDOM;
ДокументDOM = ПостроительDOM.Прочитать(ОбъектXML);
// 2. Получаем коллекцию элементов по имени тега
СписокУзлов = ДокументDOM.ПолучитьЭлементыПоИмени("ИнфПолФХЖ1");
// Проверяем, что список не пуст
Если СписокУзлов.Количество() > 0 Тогда
// 3. Извлекаем конкретный узел (родителя) из списка
РодительскийЭлемент = СписокУзлов[0];
// 4. Создаем новый элемент, который хотим вставить
НовыйЭлемент = ДокументDOM.СоздатьЭлемент("ТекстИнф");
НовыйЭлемент.УстановитьАтрибут("Идентиф", "ЗаказКлиентаНомер");
НовыйЭлемент.УстановитьАтрибут("Значен", "12345");
// 5. Добавляем созданный элемент в дерево
РодительскийЭлемент.ДобавитьДочерний(НовыйЭлемент);
КонецЕсли;
Часто возникает задача добавить информацию в каждый элемент определенной коллекции. Например, если нам нужно добавить сведения о товаре (ИнфПолФХЖ2) во все узлы СведТов. Рассмотрим, как это реализовать через обход коллекции СписокЭлементовDOM:
НужныйСписок = ДокументDOM.ПолучитьЭлементыПоИмени("СведТов");
Для Каждого ЭлементСписка Из НужныйСписок Цикл
// Для каждого существующего узла создаем свой подчиненный узел
ДопИнфо = ДокументDOM.СоздатьЭлемент("ИнфПолФХЖ2");
ДопИнфо.УстановитьАтрибут("Идентиф", "Артикул");
ДопИнфо.УстановитьАтрибут("Значен", "SKU-001");
// Добавляем к текущему элементу итерации
ЭлементСписка.ДобавитьДочерний(ДопИнфо);
КонецЦикла;
Рассмотрим дополнительные возможности 1С при работе с DOM, которые сделают ваш код более надежным и гибким:
ПолучитьЭлементыПоИмени, который ищет теги по всему документу, используйте РазыскатьУзлы(). Это позволит найти, например, только те узлы, которые находятся по строго определенному пути или имеют конкретные атрибуты.ДобавитьДочерний всегда помещает узел в конец списка детей. Если вам нужно вставить элемент в начало или перед определенным тегом, используйте метод ВставитьПеред(НовыйУзел, УзелПередКоторымВставить).<Тег>Данные</Тег>), необходимо создать текстовый узел:
ТекстовыйУзел = ДокументDOM.СоздатьТекст("МоеЗначение");
НовыйЭлемент.ДобавитьДочерний(ТекстовыйУзел);
КлонироватьУзел(Истина). Параметр Истина означает «глубокое копирование» вместе со всеми вложенными элементами и атрибутами.Выясним одну важную причину, по которой поиск элементов может не работать. Если ваш XML содержит атрибуты xmlns (пространства имен), обычный метод ПолучитьЭлементыПоИмени может вернуть пустой результат. В таких случаях мы рекомендуем использовать методы с суффиксом NS:
СоздатьЭлементNS(ПространствоИмен, КвалифицированноеИмя)ПолучитьЭлементыПоИмениNS(ПространствоИмен, ЛокальноеИмя)Проанализируем ситуацию: при работе с электронными счетами-фактурами (ЭДО) использование пространств имен является обязательным требованием. Без указания корректного URI пространства имен созданные вами элементы могут быть проигнорированы принимающей стороной.
После того как все манипуляции с деревом ДокументDOM завершены, его необходимо преобразовать обратно в строку или файл. Для этого мы используем связку ЗаписьDOM и ЗаписьXML:
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
ЗаписьDOM = Новый ЗаписьDOM;
ЗаписьDOM.Записать(ДокументDOM, ЗаписьXML);
РезультатXML = ЗаписьXML.Закрыть();
Резюмируем: Для добавления элемента в СписокЭлементовDOM, нужно сначала обратиться к конкретному элементу этого списка как к объекту типа ЭлементDOM, а затем вызвать у него метод ДобавитьДочерний(), предварительно создав новый узел через сам объект ДокументDOM.