К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как создать список XDTO в 1С

Как создать список XDTO в 1С: работа с фабрикой XDTO, добавление элементов в список, сериализация в XML, типичные ошибки и примеры кода на встроенном языке.

Механизм XDTO (XML Data Transfer Objects) в 1С используется для обмена данными с внешними системами: веб-сервисами, другими базами 1С, банками и государственными порталами. Одна из самых частых задач при такой интеграции — сформировать в XML-структуре список однотипных элементов: строки документа, перечень товаров, массив контрагентов. В терминах XDTO такой список — это свойство объекта, у которого в схеме задано множественное вхождение.

Главная сложность для начинающих разработчиков в том, что список XDTO нельзя просто заполнить присваиванием, как обычный массив. Сначала нужно получить сам объект списка через свойство владельца, а затем добавлять в него элементы методом Добавить(). Если попытаться присвоить значение напрямую, платформа выдаст ошибку, потому что свойство списка доступно только для чтения.

Ниже разобран полный цикл работы: от получения типа из фабрики XDTO до проверки результата в итоговом XML. Примеры приведены на встроенном языке 1С и подходят для любой конфигурации на управляемых формах.

Что такое список XDTO и где он описывается

Список в модели XDTO — это свойство объекта, которое может содержать несколько значений одного типа. В XML-схеме (XSD) такое свойство описывается элементом с атрибутом maxOccurs="unbounded" или с конкретным верхним ограничением. Внутри конфигурации 1С списки объявляются в пакетах XDTO, которые добавляются в ветку «XDTO-пакеты» дерева конфигурации.

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

Подготовка: пакет XDTO и типы данных

Прежде чем создавать список в коде, убедитесь, что в конфигурации есть пакет XDTO с нужной структурой. Откройте конфигуратор, перейдите в раздел «Общие — XDTO-пакеты» и проверьте, что в схеме у нужного объекта есть свойство с множественным вхождением. Если пакета нет, его можно создать вручную через конструктор или импортировать из XSD-файла, предоставленного контрагентом (например, схемой веб-сервиса).

Для примера будем считать, что есть пакет с URI пространства имён "http://example.com/orders", в нём тип Заказ со свойством-списком Товары, а элементы списка имеют тип СтрокаТовара с полями Наименование и Количество. Если имена свойств в вашей схеме на русском или английском — код адаптируется простой заменой идентификаторов.

Пошаговое создание списка XDTO

Базовый алгоритм всегда одинаковый: получаем тип объекта-владельца, создаём объект, обращаемся к свойству-списку и наполняем его. Ниже полный пример кода.

// 1. Получаем тип объекта-владельца из фабрики

ТипЗаказ = ФабрикаXDTO.Тип("http://example.com/orders", "Заказ");

// 2. Создаём объект XDTO

Заказ = ФабрикаXDTO.Создать(ТипЗаказ);

// 3. Заполняем простые свойства

Заказ.Номер = "А-001";

// 4. Обращаемся к свойству-списку и добавляем элементы

ТипСтрока = ФабрикаXDTO.Тип("http://example.com/orders", "СтрокаТовара");

Для Каждого СтрокаТовара Из ТаблицаТоваров Цикл

Элемент = ФабрикаXDTO.Создать(ТипСтрока);

Элемент.Наименование = СтрокаТовара.Наименование;

Элемент.Количество = СтрокаТовара.Количество;

Заказ.Товары.Добавить(Элемент);

КонецЦикла;

Ключевой момент — строка Заказ.Товары.Добавить(Элемент). Свойство Товары возвращает объект СписокXDTO, и именно у него вызывается метод Добавить(). Попытка написать Заказ.Товары = Элемент или присвоить массив приведёт к ошибке «Свойство доступно только для чтения».

Порядок действий
  1. 1
    Получите тип объекта-владельца через ФабрикаXDTO.Тип(URI, ИмяТипа)
  2. 2
    Создайте объект методом ФабрикаXDTO.Создать(Тип)
  3. 3
    Получите тип элемента списка из той же схемы
  4. 4
    В цикле создавайте элементы через ФабрикаXDTO.Создать() и заполняйте их свойства
  5. 5
    Добавляйте каждый элемент методом Список.Добавить(Элемент)
  6. 6
    Проверьте объект через ЗаписьXML или выгрузку в строку

Как выгрузить список в XML и проверить результат

После заполнения объект обычно сериализуется в XML — для отправки в веб-сервис или записи в файл. Используется объект ЗаписьXML с установкой соответствия пространств имён фабрики.

Запись = Новый ЗаписьXML;

Запись.УстановитьСтроку("UTF-8");

ФабрикаXDTO.ЗаписатьXML(Запись, Заказ);

СтрокаXML = Запись.Закрыть();

Сообщить(СтрокаXML); // для проверки результата

В полученном XML каждый элемент списка должен появиться отдельным тегом: если добавлено три товара, в документе будет три узла Товары внутри узла Заказ. Если узел один, хотя строк было больше — проверяйте, не создаётся ли элемент заново вместо добавления, и не теряется ли ссылка на список между итерациями.

Контрольные точки

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

Количество узлов в XML
Норма

Число тегов элемента равно числу добавленных строк

Тревожный признак

Один узел при нескольких строках или пустой список

Значения внутри узлов
Норма

Каждый узел содержит свои данные из соответствующей строки

Тревожный признак

Во всех узлах продублированы данные последней строки

Валидация по схеме
Норма

ФабрикаXDTO.Проверить() или запись проходят без исключений

Тревожный признак

Ошибка несоответствия типа или обязательного свойства

Типичные ошибки при работе со списками XDTO

Наиболее распространённая ошибка — попытка присвоить значение свойству-списку напрямую. Платформа сообщит, что свойство доступно только для чтения, потому что список является служебным объектом, управляемым фабрикой. Правильный путь — только методы Добавить(), Вставить(), Установить().

Вторая частая проблема — создание элемента списка без указания типа или с типом из другого пространства имён. Если URI в вызове ФабрикаXDTO.Тип() не совпадает с URI пакета, платформа выбросит исключение «Тип не определён». Проверяйте пространство имён в свойствах пакета XDTO в конфигураторе — оно чувствительно к регистру и лишним пробелам.

Третья группа ошибок связана с обязательными свойствами элементов. Если в схеме у типа элемента есть обязательные поля (minOccurs="1"), а вы добавили элемент, не заполнив их, ошибка проявится только при записи XML или вызове Проверить(). Поэтому полезно валидировать объект до отправки.

Типичные ошибки
01
Присваивание Заказ.Товары = Элемент вместо Заказ.Товары.Добавить(Элемент) — ошибка «свойство только для чтения»
02
Неверное пространство имён в ФабрикаXDTO.Тип() — исключение «тип не определён»
03
Создание одного элемента до цикла и многократное добавление — все узлы списка ссылаются на один объект с последними данными
04
Пропуск обязательных свойств элемента — ошибка валидации при записи XML
05
Использование глобальной фабрики вместо фабрики пакета конфигурации при нестандартных схемах

Какую фабрику XDTO использовать

В платформе доступны глобальный объект ФабрикаXDTO и отдельные фабрики, создаваемые из конкретных пакетов. Для типов, описанных в пакетах конфигурации, обычно достаточно глобальной фабрики — она включает все пакеты конфигурации и стандартные системные схемы.

Отдельная фабрика нужна, когда схема загружается динамически — например, из внешнего XSD-файла, который нельзя встраивать в конфигурацию, или когда разные версии одной схемы должны сосуществовать. В этом случае создаётся объект ФабрикаXDTO через конструктор с набором схем, и все вызовы Создать() и Тип() выполняются уже через эту переменную, а не через глобальный объект.

Сравнение вариантов

Глобальная ФабрикаXDTO

Подходит для пакетов, добавленных в конфигурацию. Проще код, не требует загрузки схем вручную. Ограничение: нельзя работать со схемами, не вшитыми в конфигурацию.

Отдельная фабрика из XSD

Подходит для динамических схем из файлов или WSDL. Гибче, но требует загрузки схемы и хранения объекта фабрики между вызовами.

WS-прокси и его фабрика

При работе через WS-ссылки типы создаются через прокси-объект. Удобно для веб-сервисов, но привязывает код к конкретному описанию сервиса.

Изменение и удаление элементов списка

Список XDTO поддерживает не только добавление. Метод Количество() возвращает число элементов, Получить(Индекс) — элемент по позиции (нумерация с нуля), Удалить(Элемент) или Удалить(Индекс) — удаление. Для замены значения по позиции используется Установить(Индекс, Элемент).

Практический сценарий: перед повторной отправкой документа нужно очистить список и заполнить его заново. Прямого метода Очистить() у СписокXDTO нет, поэтому удаление выполняется в цикле с конца: пока Количество() больше нуля, удаляется последний элемент. Либо объект-владелец создаётся заново — это проще и надёжнее, если нет необходимости сохранять остальные заполненные свойства.

При отладке удобно выводить список через цикл: Для Каждого Эл Из Заказ.Товары Цикл Сообщить(Эл.Наименование). Это быстрее показывает реальное содержимое, чем просмотр итогового XML, особенно когда документ большой.
ПЗ
Практическое замечание

Ограничения и риски

Список XDTO строго типизирован: добавить в него произвольное значение (число, строку, массив) нельзя — только объект XDTO соответствующего типа. Если по схеме элемент списка является простым типом (например, строкой), добавление выполняется напрямую значением: Список.Добавить("текст"). Уточняйте в схеме, объектный это список или список простых значений — от этого зависит синтаксис.

При больших объёмах данных (десятки тысяч элементов) учитывайте, что весь объект XDTO и итоговый XML формируются в памяти. Для очень крупных выгрузок рассмотрите потоковую запись через ЗаписьXML без промежуточного построения всего дерева объектов — это снижает потребление памяти на сервере.

Частые вопросы

Можно ли присвоить массив 1С свойству-списку XDTO?

Нет. Свойство-список доступно только для чтения и принимает элементы исключительно через методы Добавить(), Вставить() и Установить(). Массив нужно перебрать в цикле, преобразуя каждое значение в объект XDTO соответствующего типа.

Почему возникает ошибка «Тип не определён» при вызове ФабрикаXDTO.Тип()?

Причины: неверное пространство имён (проверьте URI в свойствах пакета XDTO, включая регистр символов), отсутствие типа с таким именем в схеме или использование глобальной фабрики там, где тип описан в отдельной динамически загруженной фабрике.

Как создать список простых значений, а не объектов?

Если в схеме элемент списка имеет простой тип (string, integer и т.п.), объект создавать не нужно — значение добавляется напрямую: Заказ.Теги.Добавить("срочный"). Платформа сама выполнит приведение к типу элемента.

Как очистить уже заполненный список XDTO?

Метода Очистить() у СписокXDTO нет. Удаляйте элементы в цикле с конца через Удалить() либо пересоздайте объект-владелец через ФабрикаXDTO.Создать() — второй вариант обычно проще и исключает остаточные данные.

Все узлы списка в XML содержат одинаковые данные. Что не так?

Скорее всего, элемент создан один раз вне цикла, а внутри цикла только меняются его свойства и повторно вызывается Добавить(). Создавайте новый объект элемента через ФабрикаXDTO.Создать() на каждой итерации цикла.

Чем список XDTO отличается от ТаблицаЗначений при обмене?

ТаблицаЗначений — внутренняя структура 1С, она не сериализуется в XML напрямую. Список XDTO — часть объектной модели, привязанной к XML-схеме, и автоматически преобразуется в повторяющиеся узлы при записи. Для обмена с внешними системами данные из таблиц переносятся в списки XDTO.

Итог

Что важно запомнить

Список XDTO заполняется через свойство объекта-владельца методом Добавить(), каждый элемент создаётся отдельным вызовом ФабрикаXDTO.Создать() внутри цикла. Проверяйте пространство имён, обязательные свойства и итоговый XML — большинство ошибок выявляется именно на этапе валидации.