При интеграции 1С с внешними системами через XML часто используются готовые схемы валидации XSD. Для работы с ними платформа 1С:Предприятие предоставляет удобный объект ФабрикаXDTO. Однако при программном формировании иерархических структур данных разработчики нередко сталкиваются с трудностями при заполнении вложенных списков и коллекций, получая ошибки вроде «Индекс находится за границами массива» или «Недостаточно фактических параметров».
Разберем типичную проблему и выясним причины ее возникновения, а также рассмотрим пошаговый алгоритм правильного заполнения многоуровневых структур данных XDTO.
Рассмотрим типовую ситуацию: в схеме XSD описан сложный тип (например, EmployeePaymentsType), содержащий свойство ListOfDeduction, внутри которого находится список элементов вычетов Deductions с реквизитами Deduction и Amount.
Частая ошибка заключается в попытке обратиться к первому элементу вложенного списка напрямую через индекс сразу после создания родительского объекта:
Вычеты = ФабрикаXDTO.Создать(ФабрикаXDTO.Пакеты.Получить("http://test").Получить("EmployeePaymentsType").Свойства.Получить("ListOfDeduction").Тип);
Вычеты.Deductions[0].Deduction = "dddd"; // Вызовет ошибку "Индекс находится за границами массива"
Проанализируем, почему этот код не работает:
Deductions инициализируется как пустая коллекция типа СписокXDTO. В ней еще нет ни одной строки, поэтому обращение к [0] приводит к выходу за границы массива.Вычеты.Deductions.Добавить() без параметров также приводит к ошибке «Недостаточно фактических параметров», поскольку метод Добавить() у объекта СписокXDTO обязательно ожидает готовый экземпляр значения или вложенного объекта типа ОбъектXDTO.Разберем по шагам, как корректно инициализировать и наполнять вложенные списки XDTO любого уровня вложенности.
ФабрикаXDTO.Тип(URI, ИмяТипа), а для локального — получаем его через метаданные свойства родителя: ОбъектРодитель.Свойства.Получить("ИмяСвойства").Тип.ФабрикаXDTO.Создать(ТипЭлемента).Добавить() у свойства-списка, передавая ему подготовленный экземпляр: СписокXDTO.Добавить(НовыйЭлемент).Посмотрим на практический пример кода, который формирует дерево элементов и корректно заполняет вложенные реквизиты:
// 1. Создаем родительский объект
URIПространства = "http://test";
ТипПлатежей = ФабрикаXDTO.Тип(URIПространства, "EmployeePaymentsType");
ПлатежиСотрудника = ФабрикаXDTO.Создать(ТипПлатежей);
// 2. Создаем контейнер для вычетов (ListOfDeduction)
ТипСпискаВычетов = ПлатежиСотрудника.Свойства.Получить("ListOfDeduction").Тип;
Вычеты = ФабрикаXDTO.Создать(ТипСпискаВычетов);
// 3. Получаем тип отдельной строки вычета (Deductions)
ТипСтрокиВычета = Вычеты.Свойства.Получить("Deductions").Тип;
// 4. Создаем и заполняем строки списка
Для Каждого СтрокаТЧ Из ТаблицаДанных Цикл
СтрокаВычета = ФабрикаXDTO.Создать(ТипСтрокиВычета);
СтрокаВычета.Deduction = СтрокаТЧ.КодВычета;
СтрокаВычета.Amount = СтрокаТЧ.СуммаВычета;
// Помещаем созданный объект в коллекцию СписокXDTO
Вычеты.Deductions.Добавить(СтрокаВычета);
КонецЦикла;
// 5. Привязываем контейнер вычетов к родительскому объекту
ПлатежиСотрудника.ListOfDeduction = Вычеты;
После того как структура XDTO полностью заполнена данными, выполним проверку корректности и сформируем итоговый файл выгрузки.
ФабрикаXDTO.Проверить(ОбъектXDTO) позволяет убедиться, что все обязательные поля (согласно правилам XSD) заполнены, типы соответствуют ограничениям, а количество элементов в списках не нарушает спецификацию.ЗаписьXML и метода ФабрикаXDTO.ЗаписатьXML():
// Проверяем соответствие схеме XSD
ФабрикаXDTO.Проверить(ПлатежиСотрудника);
// Записываем результат на диск
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("C:\Exchange\Export.xml", "UTF-8");
ФабрикаXDTO.ЗаписатьXML(ЗаписьXML, ПлатежиСотрудника);
ЗаписьXML.Закрыть();
В случаях, когда схема XSD имеет чрезмерно сложную и запутанную структуру со множеством анонимных типов, разработка через ФабрикаXDTO может оказаться трудоемкой. В таких ситуациях рассмотрим альтернативные подходы:
ЗаписьXML. Формирование документа методами ЗаписатьНачалоЭлемента(), ЗаписатьТекст(), ЗаписатьАтрибут() и ЗаписатьКонецЭлемента(). Этот способ работает быстрее по производительности и не требует динамического определения типов.ДокументDOM). Позволяет формировать XML-дерево из узлов и элементов в памяти произвольным образом без строгой типизации XDTO.