Как устроена работа с XDTO в 1С:Предприятии 8.3 — от XSD-схемы до обмена

· 9 мин

Содержание

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

Частое заблуждение: «XDTO — это для веб-сервисов, для обычного обмена хватит ЗаписьXML». На деле XDTO выгоднее и в файловом обмене. Схема сама проверяет обязательные поля, типы и порядок элементов, а вы не пишете сотни строк ручного разбора узлов.

Из чего состоит XDTO: модель типов и данных

XDTO (XML Data Transfer Objects) описывает данные так же, как XML Schema. Есть пространство имён (URI), в нём — типы, у типов — свойства.

Типы делятся на два вида:

  • 🧱 Тип значения (ТипЗначенияXDTO) — простое значение: строка, число, дата, перечисление с фасетами (длина, шаблон, список допустимых значений).
  • 📦 Тип объекта (ТипОбъектаXDTO) — составной объект со свойствами. Свойство может хранить значение или вложенный объект.

У каждого свойства есть важные характеристики:

ХарактеристикаЧто задаётЧем грозит ошибка
Нижняя граница0 — необязательное, 1 — обязательноеПроверка падает, если поле не заполнено
Верхняя граница1 — одно значение, -1 — списокПри -1 свойство становится СписокXDTO
Возможно пустое (nillable)Допускает xsi:nil="true"Без него пустой элемент не пройдёт проверку
ФормаЭлемент, атрибут или текстАтрибут нельзя прочитать как элемент

Соответствие типов XML Schema и 1С простое: xs:string → Строка, xs:decimal и xs:int → Число, xs:dateTime и xs:date → Дата, xs:boolean → Булево. Двоичные данные (xs:base64Binary) превращаются в ДвоичныеДанные.

Когда в коде вы обращаетесь Объект.Номер, платформа ищет свойство по имени из схемы. Регистр букв важен: number и Number — разные свойства.

Как создать XDTO-пакет и подключить XSD-схему

Есть два пути. Первый — статический пакет в конфигурации. Второй — фабрика, собранная из XSD прямо во время работы.

XDTO-пакет в конфигураторе

  1. Откройте конфигурацию в конфигураторе.
  2. В дереве перейдите в Общие → XDTO-пакеты.
  3. Если у вас есть готовая XSD от контрагента или госоргана, вызовите контекстное меню ветки и выберите импорт XML-схемы. Пакет и все типы создадутся автоматически.
  4. Если схемы нет, добавьте пакет вручную, задайте URI пространства имён (например, http://example.org/orders/1.0) и опишите типы в редакторе пакета.
  5. Обновите конфигурацию базы данных.

После этого типы пакета доступны через глобальную ФабрикаXDTO без дополнительных действий.

Если вы правите типовую конфигурацию, добавление пакета снимает её с полной поддержки в этой части. Для типовых баз удобнее второй путь — фабрика из XSD-файла, которая ничего не меняет в конфигурации.

Фабрика из XSD без изменения конфигурации

Схему можно прочитать из файла и построить отдельную фабрику. Это удобно в обработках и расширениях.

Функция ФабрикаИзXSD(ПутьКФайлуXSD)

    Чтение = Новый ЧтениеXML;
    Чтение.ОткрытьФайл(ПутьКФайлуXSD);

    ПостроительDOM = Новый ПостроительDOM;
    ДокументDOM = ПостроительDOM.Прочитать(Чтение);
    Чтение.Закрыть();

    ПостроительСхем = Новый ПостроительСхемXML;
    Схема = ПостроительСхем.СоздатьСхемуXML(ДокументDOM);

    НаборСхем = Новый НаборСхемXML;
    НаборСхем.Добавить(Схема);

    Возврат Новый ФабрикаXDTO(НаборСхем);

КонецФункции

Если схема импортирует другие XSD (xs:import), добавьте в НаборСхем все файлы, иначе фабрика не найдёт внешние типы.

Как создать и заполнить объект по типу

URI = "http://example.org/orders/1.0";

ТипЗаказ   = ФабрикаXDTO.Тип(URI, "Order");
ТипСтрока  = ФабрикаXDTO.Тип(URI, "OrderLine");

Заказ = ФабрикаXDTO.Создать(ТипЗаказ);
Заказ.Number = "ЗК-000125";
Заказ.Date   = ТекущаяДатаСеанса();

СтрокаЗаказа = ФабрикаXDTO.Создать(ТипСтрока);
СтрокаЗаказа.Sku      = "A-100";
СтрокаЗаказа.Quantity = 3;
СтрокаЗаказа.Price    = 1250.50;

// Свойство Lines имеет верхнюю границу -1, это СписокXDTO
Заказ.Lines.Добавить(СтрокаЗаказа);

Для свойства-списка нельзя писать Заказ.Lines = СтрокаЗаказа: так вы перезапишете список одним элементом или получите ошибку типа. Только Добавить().

Сериализация и десериализация объектов через XDTO

Здесь две разные задачи, и их часто путают.

ЗадачаЧем делатьЧто получится
Выгрузить справочник или документ «как есть»СериализаторXDTOXML в пространстве имён платформы, ссылки в виде UUID
Сформировать файл по чужой схемеФабрикаXDTO + свой пакетXML строго по XSD контрагента
Передать объект в JSONСериализаторXDTO.ЗаписатьJSONJSON с типами платформы

Объект XDTO → XML-строка и обратно

Запись = Новый ЗаписьXML;
Запись.УстановитьСтроку("UTF-8");
Запись.ЗаписатьОбъявлениеXML();
ФабрикаXDTO.ЗаписатьXML(Запись, Заказ, "Order", URI);
ТекстXML = Запись.Закрыть();

Чтение выполняется зеркально:

Чтение = Новый ЧтениеXML;
Чтение.УстановитьСтроку(ТекстXML);
Заказ = ФабрикаXDTO.ПрочитатьXML(Чтение, ФабрикаXDTO.Тип(URI, "Order"));
Чтение.Закрыть();

Для Каждого СтрокаЗаказа Из Заказ.Lines Цикл
    Сообщить(СтрокаЗаказа.Sku + ": " + Формат(СтрокаЗаказа.Quantity, "ЧГ=0"));
КонецЦикла;

Объекты конфигурации через СериализаторXDTO

Глобальный СериализаторXDTO умеет записывать почти любой объект конфигурации, ссылку, таблицу значений, структуру или набор записей регистра.

// Выгрузка элемента справочника
Объект = Ссылка.ПолучитьОбъект();
Запись = Новый ЗаписьXML;
Запись.ОткрытьФайл("C:\Exchange\item.xml");
СериализаторXDTO.ЗаписатьXML(Запись, Объект, НазначениеТипаXML.Явное);
Запись.Закрыть();

// Загрузка в другой базе с той же структурой
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл("C:\Exchange\item.xml");
Объект = СериализаторXDTO.ПрочитатьXML(Чтение);
Чтение.Закрыть();

Объект.ОбменДанными.Загрузка = Истина;
Объект.Записать();

Флаг ОбменДанными.Загрузка = Истина отключает проверки и бизнес-логику в обработчиках записи. Так работают типовые механизмы выгрузки и загрузки данных.

Загрузка с флагом Загрузка = Истина пропускает проверку заполнения и проведение — сначала прогоните её на копии базы.

Важные особенности этого приёма:

  • 🔑 Ссылки пишутся по UUID. Если в базе-приёмнике нет объекта с таким UUID, после загрузки останется «битая» ссылка.
  • 🧩 Структура метаданных в обеих базах должна совпадать. Лишний реквизит в XML вызовет ошибку чтения.
  • 🔄 Для JSON используйте ЗаписьJSON и СериализаторXDTO.ЗаписатьJSON(Запись, Значение, НазначениеТипаXML.Явное); чтение — СериализаторXDTO.ПрочитатьJSON.

НазначениеТипаXML.Явное добавляет атрибут xsi:type. Без него при чтении значения составного типа (например, реквизита «Строка или Число») платформа не сможет понять, что лежит в элементе.

Проверка данных и обработка ошибок XDTO

XDTO проверяет данные в двух местах: при чтении XML и по команде Проверить(). Пользуйтесь вторым до отправки — так ошибка всплывёт у вас, а не на стороне получателя.

Попытка
    Заказ.Проверить();
Исключение
    ТекстОшибки = ОписаниеОшибки();
    ЗаписьЖурналаРегистрации("Обмен.XDTO", УровеньЖурналаРегистрации.Ошибка,,,
        "Заказ " + Заказ.Number + ": " + ТекстОшибки);
    ВызватьИсключение;
КонецПопытки;

Проверить() смотрит обязательные свойства, количество элементов в списках, фасеты простых типов (длина строки, шаблон, перечисление допустимых значений).

Чтение XML тоже оборачивайте в Попытка. Сообщения платформы начинаются с Ошибка преобразования данных XDTO или Ошибка проверки данных XDTO, дальше идут имя свойства и тип. Эту часть и надо читать.

Диагностика: выберите симптом

Пустой элемент <Comment/> и отсутствующий элемент — не одно и то же. Если получатель ждёт пустой элемент, а свойство не помечено как nillable, присвойте пустую строку, а не Неопределено.

XDTO в веб-сервисах и HTTP-запросах

Свой веб-сервис на 1С

  1. В Общие → Web-сервисы добавьте сервис, задайте URI пространства имён.
  2. В свойстве сервиса укажите XDTO-пакеты, типы которых будут параметрами и результатами.
  3. Опишите операции, для параметров выберите типы из пакета.
  4. Опубликуйте базу: Администрирование → Публикация на веб-сервере в конфигураторе.

В модуле операции параметр приходит уже готовым ОбъектXDTO. Возвращаете тоже объект, созданный через фабрику:

Функция ПолучитьЗаказ(НомерЗаказа)
    Ответ = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(URI, "Order"));
    Ответ.Number = НомерЗаказа;
    // ... заполнение из базы
    Возврат Ответ;
КонецФункции

Подключение к чужому SOAP-сервису

Динамически, по адресу WSDL:

Определения = Новый WSОпределения("https://partner.example/ws/orders?wsdl");
Прокси = Новый WSПрокси(Определения,
    "http://example.org/orders/1.0", "OrderService", "OrderServiceSoap");

Заказ = Прокси.ФабрикаXDTO.Создать(
    Прокси.ФабрикаXDTO.Тип("http://example.org/orders/1.0", "Order"));

Берите Прокси.ФабрикаXDTO, а не глобальную ФабрикаXDTO: типы чужого сервиса есть только в фабрике прокси.

Статический вариант — импортировать WSDL в Общие → WS-ссылки. Тогда прокси создаётся через WSСсылки.<ИмяСсылки>.СоздатьWSПрокси(URI, ИмяСервиса, ИмяТочки) и WSDL не скачивается при каждом вызове.

REST и HTTP с XML-телом

Для HTTP-сервиса XDTO даёт только формирование и разбор тела. Транспорт — HTTPСоединение и HTTPЗапрос:

Запрос = Новый HTTPЗапрос("/api/orders");
Запрос.Заголовки.Вставить("Content-Type", "application/xml; charset=utf-8");
Запрос.УстановитьТелоИзСтроки(ТекстXML, КодировкаТекста.UTF8);

Соединение = Новый HTTPСоединение("partner.example", 443,,,,, Новый ЗащищенноеСоединениеOpenSSL);
Ответ = Соединение.ОтправитьДляОбработки(Запрос);

Если Ответ.КодСостояния = 200 Тогда
    Чтение = Новый ЧтениеXML;
    Чтение.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку());
    Результат = ФабрикаXDTO.ПрочитатьXML(Чтение, ФабрикаXDTO.Тип(URI, "OrderResult"));
КонецЕсли;

Проверяйте код ответа до разбора. Иначе на 500 вы получите HTML-страницу ошибки и запутанное исключение XDTO вместо понятного сообщения.

Большие объёмы данных: как ускорить XDTO

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

  • ⏱ Получайте типы один раз. ФабрикаXDTO.Тип() внутри цикла на 100 000 строк — лишние 100 000 поисков. Сохраните тип в переменную до цикла.
  • 💾 Пишите в файл, а не в строку. УстановитьСтроку() держит весь документ в памяти. ОткрытьФайл() пишет потоком.
  • 📖 Не читайте большой файл через DOM. ПостроительDOM грузит весь документ в память. Читайте потоком и разбирайте через XDTO по одному элементу.
  • 🌐 Кешируйте прокси. Новый WSОпределения каждый раз скачивает WSDL. Создайте прокси один раз на сеанс или используйте WS-ссылку.
  • 📦 Режьте пакеты. Отправка 50 000 строк одним SOAP-вызовом упирается в таймауты. Разбейте на порции по 500–1000 объектов.

Потоковое чтение крупного файла по элементам:

ТипСтрока = ФабрикаXDTO.Тип(URI, "OrderLine");

Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл("C:\Exchange\big.xml");

ЕстьУзел = Чтение.Прочитать();
Пока ЕстьУзел Цикл
    Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента
        И Чтение.ЛокальноеИмя = "OrderLine" Тогда
        // ПрочитатьXML сам переводит чтение за конец элемента
        СтрокаЗаказа = ФабрикаXDTO.ПрочитатьXML(Чтение, ТипСтрока);
        ОбработатьСтроку(СтрокаЗаказа);
    Иначе
        ЕстьУзел = Чтение.Прочитать();
    КонецЕсли;
КонецЦикла;

Чтение.Закрыть();

Обратите внимание на ветку Иначе. Если звать Прочитать() сразу после ПрочитатьXML, вы перескочите следующий элемент OrderLine, когда он идёт вплотную к предыдущему. Это частая причина «потерянных» строк при загрузке.

При загрузке тысяч объектов через СериализаторXDTO записывайте их порциями в транзакциях по 100–500 штук. Одна огромная транзакция держит блокировки и при сбое откатывается вся.

Частые ошибки при работе с XDTO

  • ❌ Глобальная фабрика вместо фабрики прокси. Тип «не найден», хотя он есть в WSDL.
  • ❌ Разные URI в пакете и в файле. Достаточно отличия в одном символе или завершающем слэше — и XML не читается.
  • ❌ Присвоение списка вместо Добавить(). Остаётся один элемент или возникает ошибка типа.
  • ❌ Склейка числа со строкой без формата. "Количество: " + 1500 даст 1 500 с неразрывным пробелом, а получатель ждёт 1500. Используйте Формат(Число, "ЧГ=0") или присваивайте число в свойство числового типа.
  • ❌ Нет НазначениеТипаXML.Явное для составных типов. Выгрузка проходит, а загрузка падает или ставит не тот тип.
  • ❌ Правка XSD без версии. Меняете схему — меняйте URI (/1.0 → /1.1), чтобы старые и новые клиенты не ломали друг друга.

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

Чем XDTO отличается от обычной ЗаписьXML?
ЗаписьXML пишет узлы по одному, структуру вы контролируете сами. XDTO строит документ по схеме и проверяет типы, обязательность и порядок элементов.
Можно ли использовать XDTO в расширении конфигурации?
Да. Самый безопасный вариант для типовых баз — собрать фабрику из XSD-файла в коде расширения, ничего не меняя в основной конфигурации.
Как посмотреть, какие типы есть в фабрике?
Переберите ФабрикаXDTO.Пакеты, у каждого пакета — коллекцию типов. Удобно для отладки, когда неясно, какой URI использовать.
Подходит ли XDTO для JSON?
Да, для объектов платформы: у СериализаторXDTO есть ЗаписатьJSON и ПрочитатьJSON. Для чужого JSON без схемы проще ПрочитатьJSON в структуру или соответствие.
Почему после загрузки через СериализаторXDTO в реквизитах «Объект не найден»?
Ссылки загружаются по UUID. Выгрузите и загрузите связанные объекты тоже, начиная со справочников, на которые ссылаются документы.