При генерации выгрузок XML с использованием механизма XDTO в 1С разработчики часто сталкиваются с ситуацией, когда вместо уникальных узлов в итоговом файле формируются повторяющиеся строки с одинаковыми значениями — равными последней обработанной строке.
Рассмотрим, почему возникает эта проблема, проанализируем механизмы работы платформы с объектами XDTO и разберем правильные способы заполнения коллекций в цикле.
Выясним, почему вызов метода добавления элемента в коллекцию приводит к перезаписи предыдущих данных. В платформе 1С объекты типа ОбъектXDTO представляют собой ссылочные типы данных.
Если объект создается единожды перед началом цикла, а затем в цикле меняются его свойства и вызывается метод Добавить(), платформа добавляет в коллекцию не новую независимую копию, а повторную ссылку на один и тот же объект в оперативной памяти. В результате на каждой итерации цикла вы меняете свойства одного единственного экземпляра, что визуально отображается как перезапись всех элементов XML-дерева значением из последней строки.
Пример некорректного кода, приводящего к дублированию:
// Неправильный подход: XML_Row создан один раз вне цикла
Для Каждого СтрТЧ Из ТЧ Цикл
XML_Row.Code = СтрТЧ.Code;
XML_Document.SupplierInfo.Merchandises.Row.Добавить(XML_Row);
КонецЦикла;
Чтобы каждая строка XML содержала собственные уникальные данные, необходимо на каждой итерации цикла инстанцировать новый экземпляр объекта XDTO. При этом пересоздавать весь родительский XML-документ не требуется.
Разберем, как правильно реализовать заполнение коллекции через фабрику XDTO:
// 1. Получаем тип создаваемого узла из фабрики XDTO или метаданных
ТипСтроки = ФабрикаXDTO.Тип("http://www.example.com/supplier", "RowType");
Для Каждого СтрТЧ Из ТЧ Цикл
// 2. Внутри цикла создаем НОВЫЙ экземпляр объекта
НоваяСтрока = ФабрикаXDTO.Создать(ТипСтроки);
НоваяСтрока.Code = СтрТЧ.Code;
// 3. Добавляем новый объект в коллекцию родителя
XML_Document.SupplierInfo.Merchandises.Row.Добавить(НоваяСтрока);
КонецЦикла;
Также тип вложенного элемента можно получить непосредственно из метаданных свойства родительского объекта, если exact-имя типа в пространстве имен неизвестно:
СвойствоRow = XML_Document.SupplierInfo.Merchandises.Свойства().Получить("Row");
ТипЭлементаRow = СвойствоRow.Тип;
Для Каждого СтрТЧ Из ТЧ Цикл
НоваяСтрока = ФабрикаXDTO.Создать(ТипЭлементаRow);
НоваяСтрока.Code = СтрТЧ.Code;
XML_Document.SupplierInfo.Merchandises.Row.Добавить(НоваяСтрока);
КонецЦикла;
Проанализируем важные нюансы работы с объектами XDTO, о которых необходимо помнить при проектировании интеграций:
ЗаполнитьЗначенияСвойств() копирует только простые (атомарные) свойства, но не создаст дубликаты для вложенных списков или сложных структур.ЗаписьXML: Для большеобъемных файлов рекомендуется отказаться от формирования XDTO-дерева в пользу последовательной записи через объект ЗаписьXML (методы ЗаписатьНачалоЭлемента, ЗаписатьАтрибут, ЗаписатьКонецЭлемента). Это позволяет генерировать гигабайтные файлы с минимальным расходом памяти.СериализаторXDTO: Если выгружаемые данные соответствуют стандартным объектам платформы 1С, их можно записывать прямо в поток ЗаписьXML с помощью сериализатора, избегая ручного конструирования каждого узла.