XDTO-пакеты: как 1С описывает и разбирает XML при обмене

· 10 мин

Содержание

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

Зачем они нужны: чтобы обмен с другой системой шёл по строгой схеме. Вы собираете объект по типу из пакета, платформа проверяет его и пишет корректный XML. На входе — наоборот: XML разбирается в объект, к свойствам которого обращаются через точку. Ручной разбор тегов через ЧтениеXML и склейка строк больше не нужны.

Что внутри XDTO-пакета и как устроена модель

XDTO расшифровывается как XML Data Transfer Objects. Модель держится на трёх уровнях.

  • 🏭 Фабрика XDTO (ФабрикаXDTO) — хранилище всех известных типов. Глобальная фабрика содержит пакеты конфигурации и служебные пакеты платформы. Создаёт объекты и читает/пишет XML.
  • 📦 Пакет XDTO — набор типов с одним URI пространства имён. Один пакет обычно соответствует одной XSD-схеме.
  • 🧩 Типы — два вида: типы значений и типы объектов.
ЭлементЧему соответствует в XSDЧто получится в коде
Тип значения (ТипЗначенияXDTO)simpleTypeСтрока, Число, Дата, Булево, ДвоичныеДанные
Тип объекта (ТипОбъектаXDTO)complexTypeОбъектXDTO со свойствами
Свойство с верхней границей больше 1элемент с maxOccurs > 1СписокXDTO
Свойство пакета (корневое)глобальный elementточка входа документа

Свойства типа объекта

У каждого свойства задаются имя, тип, нижняя и верхняя граница. Нижняя граница 0 — свойство необязательное. Верхняя граница -1 — список без ограничения.

Ещё есть форма: элемент, атрибут или текст. От неё зависит, как свойство попадёт в XML — тегом <Number> или атрибутом Number="...".

У самого типа объекта есть флаги. Самые полезные:

  • Открытый — объект может содержать свойства, которых нет в описании. Полезно, когда партнёр добавляет новые поля, а ваш разбор не должен из-за этого падать.
  • Упорядоченный — порядок свойств в XML строго как в описании.
  • Абстрактный — тип только для наследования, создать его экземпляр нельзя.

Типы значений сужают базовый тип фасетами: длина строки, шаблон, перечисление допустимых значений, число знаков. Например, ИНН — строка длиной 10 или 12 по шаблону из цифр.

Как создать пакет XDTO в конфигураторе

Пакет можно описать вручную или получить из готовой схемы. Второй путь быстрее и надёжнее, если партнёр прислал XSD.

Импорт из XSD

  1. В дереве конфигурации раскройте Общие и найдите ветку XDTO-пакеты.
  2. Вызовите контекстное меню на ветке и выберите Импорт XML-схемы....
  3. Укажите файл .xsd. Платформа создаст пакет с пространством имён из targetNamespace схемы.
  4. Откройте пакет и проверьте, что все типы и свойства на месте.
  5. Сохраните конфигурацию и обновите конфигурацию базы данных.

Если схема ссылается на другие схемы через import, сначала загрузите их. Иначе пакет не найдёт внешние типы. Связь между пакетами задаётся в редакторе пакета как импорт другого пространства имён.

Ручное описание

Для небольшого формата проще собрать пакет руками:

  1. Создайте новый XDTO-пакет и задайте пространство имён, например http://example.ru/order. Это URI-идентификатор, по нему ничего не скачивается.
  2. В редакторе пакета добавьте типы значений, затем типы объектов.
  3. У каждого типа объекта добавьте свойства и задайте им тип и границы.
  4. Добавьте корневое свойство пакета, если документ должен начинаться с конкретного элемента.

Обратная операция тоже есть: из пакета можно выгрузить схему командой Экспорт XML-схемы... и отдать её партнёру. В коде то же делает ФабрикаXDTO.ЭкспортСхемыXML(URI).

💡 URI пространства имён сразу выбирайте окончательный. Он попадает во все XML-документы. Смена URI потом ломает обмен у второй стороны.

Сериализация и десериализация: два пути

Здесь чаще всего путаются. У XDTO два разных механизма, и решают они разные задачи.

МеханизмЧто превращает в XMLКогда применять
ФабрикаXDTO + ваш пакетОбъектXDTO, собранный по вашей схемеОбмен с внешней системой по согласованному формату
СериализаторXDTOОбъекты самой 1С: справочники, документы, ссылки, структуры, таблицыПеренос данных между базами 1С с одинаковыми метаданными

СериализаторXDTO

Сериализатор работает со служебными пакетами платформы, ваш пакет ему не нужен. Он пишет объект конфигурации целиком, со всеми реквизитами и табличными частями.

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

Обратно:

Чтение = Новый ЧтениеXML;
Чтение.УстановитьСтроку(ТекстXML);
Объект = СериализаторXDTO.ПрочитатьXML(Чтение);
Объект.ОбменДанными.Загрузка = Истина;
Объект.Записать();

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

Глобальные функции ЗаписатьXML() и ПрочитатьXML() — короткая запись того же сериализатора.

У сериализатора есть и промежуточный шаг: ЗаписатьXDTO() превращает значение в ОбъектXDTO, а ПрочитатьXDTO() делает обратное. Это удобно, когда объект 1С надо вложить в свой XDTO-объект как свойство.

Фабрика и свой пакет

Фабрика читает и пишет XML по типам вашего пакета. Структура документа диктуется схемой, а не метаданными 1С. Этим путём делают обмен с сайтами, банками, маркетплейсами, госсистемами и любыми не-1С системами.

Объекты XDTO в коде: создание, заполнение, проверка

Возьмём пакет с пространством имён http://example.ru/order. В нём тип Order со свойствами Number, Date и списком Item (верхняя граница -1). Тип строки OrderItem содержит Sku и Qty.

Собрать и записать

URI = "http://example.ru/order";
ТипЗаказ   = ФабрикаXDTO.Тип(URI, "Order");
ТипПозиция = ФабрикаXDTO.Тип(URI, "OrderItem");

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

Для Каждого Строка Из Товары Цикл
    Позиция = ФабрикаXDTO.Создать(ТипПозиция);
    Позиция.Sku = Строка.Артикул;
    Позиция.Qty = Строка.Количество;
    Заказ.Item.Добавить(Позиция);
КонецЦикла;

Заказ.Проверить(); // исключение, если объект не соответствует схеме

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

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

Прочитать входящий XML

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

Для Каждого Позиция Из Заказ.Item Цикл
    // Позиция.Sku, Позиция.Qty уже приведены к типам из схемы
КонецЦикла;

Полезные приёмы

  • 🔍 Объект.Свойства() возвращает описание свойств типа. Так можно обойти объект, не зная заранее его структуру.
  • 📝 Обращение через точку работает, если имя свойства — допустимый идентификатор. Для имён с дефисом используйте Объект.Получить("order-id") и Объект.Установить("order-id", Значение).
  • 🏷 Префиксы пространств имён в выходном XML задаются методом ЗаписьXML.ЗаписатьСоответствиеПространстваИмен(Префикс, URI). Без него платформа сгенерирует служебные префиксы — XML будет корректным, но некоторые партнёры такой не принимают.
  • 🧪 Если XSD приходит в рантайме и в конфигурацию его не добавить, соберите отдельную фабрику: схему читают через ПостроительСхемXML, кладут в НаборСхемXML и передают в конструктор Новый ФабрикаXDTO(НаборСхем).
Перед отправкой XDTO-объекта
Выполнено: 0 / 6

Типы данных XDTO и передача ссылок

Простые типы XML Schema платформа приводит к своим автоматически.

Тип XML SchemaТип в 1С
xs:stringСтрока
xs:decimal, xs:int, xs:longЧисло
xs:dateTime, xs:dateДата
xs:booleanБулево
xs:base64BinaryДвоичныеДанные

Если в схеме свойство помечено как допускающее пустое значение (nillable), в XML оно запишется с xsi:nil="true". Это не то же самое, что отсутствие свойства. Партнёр может различать «поле не передано» и «поле передано пустым», поэтому договоритесь заранее, что значит каждое.

Как сериализуются ссылки

Ссылка на справочник или документ при записи через СериализаторXDTO превращается в строку с уникальным идентификатором (GUID). Типы объектов базы лежат в служебном пространстве имён http://v8.1c.ru/8.1/data/enterprise/current-config и называются по шаблону CatalogRef.Номенклатура, DocumentObject.РеализацияТоваровУслуг.

При чтении сериализатор восстанавливает ссылку по GUID. Наличие объекта в базе при этом не проверяется. Если такого элемента нет, вы получите битую ссылку, которая в формах показывается как «Объект не найден».

Отсюда правило: при переносе данных между базами сначала загружайте справочники, потом документы. Или проверяйте ссылку после чтения и создавайте недостающий элемент с тем же идентификатором через ПолучитьСсылку(Новый УникальныйИдентификатор(Строка)) и УстановитьСсылкуНового().

В обмене с внешней системой GUID 1С обычно бесполезен. Там передают артикул, ИНН или внешний код, а ссылку ищут на своей стороне. Свой пакет XDTO описывает именно такие поля, а не ссылки.

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

Веб-сервисы конфигурации

Объект метаданных «Web-сервис» в свойствах содержит список XDTO-пакетов. Типы параметров и возвращаемых значений операций выбираются из этих пакетов. При публикации платформа сама формирует WSDL на их основе.

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

Вызов чужого SOAP-сервиса идёт через прокси:

Определения = Новый WSОпределения("https://partner.example.ru/ws/orders?wsdl", Логин, Пароль);
Прокси = Новый WSПрокси(Определения, "http://partner.example.ru/orders", "OrdersService", "OrdersServiceSoap");
Прокси.Пользователь = Логин;
Прокси.Пароль = Пароль;

Фабрика = Прокси.ФабрикаXDTO; // типы из WSDL партнёра
Запрос = Фабрика.Создать(Фабрика.Тип("http://partner.example.ru/orders", "GetOrderRequest"));

Здесь важная деталь: у прокси своя фабрика, собранная из WSDL. Типы партнёра берут из Прокси.ФабрикаXDTO, а не из глобальной ФабрикаXDTO. Пакет в конфигурацию добавлять не нужно.

Пространство имён, имя сервиса и точки подключения смотрите в самом WSDL: атрибут targetNamespace, элементы service и port.

HTTP-запросы и REST с XML

Если партнёр принимает XML через обычный POST, XDTO сериализует тело, а транспорт берёт на себя HTTPСоединение:

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

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

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

Ответ разбирают так же, как входящий файл: ЧтениеXML.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку()), затем ФабрикаXDTO.ПрочитатьXML() с нужным типом.

В HTTP-сервисах конфигурации пакеты XDTO к сервису не привязываются. Тело запроса вы читаете сами и передаёте в фабрику.

Для JSON у сериализатора есть методы ЗаписатьJSON() и ПрочитатьJSON() (платформа 8.3.6 и выше). Они пишут объекты 1С в собственном формате платформы. Для обмена с внешним REST API JSON обычно собирают через ЗаписьJSON и структуры, без XDTO.

Как ускорить обмен через XDTO

XDTO удобен, но не бесплатен. На больших объёмах узкие места видны быстро.

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

Потоковое чтение большого файла

Приём: идём по файлу обычным ЧтениеXML, а когда курсор встаёт на начало нужного элемента, отдаём его фабрике. Фабрика читает только этот элемент, память не растёт.

Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ИмяФайла);
ТипПозиция = ФабрикаXDTO.Тип(URI, "OrderItem");

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

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

После ПрочитатьXML() читатель уже стоит за прочитанным элементом. Поэтому Прочитать() вызывается только в ветке Иначе — так соседний элемент не пропустится.

💡 Записывать в базу удобнее порциями внутри транзакции, например по 500–1000 объектов. Одна транзакция на весь файл держит блокировки слишком долго.

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

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

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

Можно ли изменить пакет XDTO без обновления конфигурации базы?
Нет. Пакет — объект метаданных, изменения вступят в силу после обновления конфигурации базы данных. Для схем, которые часто меняются, собирайте фабрику из XSD в коде.
Чем XDTO отличается от ЧтениеXML и ЗаписьXML?
ЧтениеXML и ЗаписьXML работают с узлами и тегами. XDTO работает с объектами по схеме: проверяет структуру и типы, а свойства доступны по имени.
Нужен ли пакет XDTO для обмена между базами 1С?
Не обязательно. При одинаковых метаданных хватит СериализаторXDTO. Пакет нужен, когда формат задан внешней схемой или базы различаются по структуре.
Можно ли изменить пакет в расширении конфигурации?
Расширение может содержать собственные XDTO-пакеты. Новый формат обмена удобно добавлять именно так, не снимая основную конфигурацию с поддержки.
Где посмотреть, какие пакеты знает фабрика?
Обойдите коллекцию ФабрикаXDTO.Пакеты: у каждого пакета есть URI пространства имён и список типов.