Запись объекта XDTO в XML-файл: пакет, код, HTTP-сервис и расписание

· 9 мин

Содержание

Чтобы сохранить XDTO в файл в 1С, откройте ЗаписьXML на нужный путь и вызовите ФабрикаXDTO.ЗаписатьXML(ЗаписьXML, ОбъектXDTO), после чего закройте запись методом Закрыть(). Если у вас не свой объект XDTO, а обычный документ или справочник, вместо фабрики используйте СериализаторXDTO.ЗаписатьXML(ЗаписьXML, Объект).

Всё остальное — детали: откуда взять тип, как заполнить вложенные списки, где выполнять код в тонком клиенте и как выгружать файл без участия человека. Механизм общий для платформы 8.3 и не зависит от конфигурации: одинаково работает в БП 3.0, ЗУП 3.1, УТ 11 и в самописных базах.

Подготовка: XDTO-пакет и описание типов

XDTO-пакет — это схема: какие элементы будут в файле, какого они типа и сколько раз могут повторяться. Без схемы фабрика не знает, что создавать. Взять её можно тремя путями.

1. Создать пакет в конфигураторе. В дереве метаданных откройте ветку Общие → XDTO-пакеты и добавьте новый пакет. В его свойствах обязательно задайте пространство имён (URI), например http://example.ru/export/orders. По этому URI код потом будет искать типы.

2. Импортировать готовую XSD-схему. Если формат файла задаёт контрагент или госсервис, схему не рисуют руками. В контекстном меню ветки XDTO-пакетов есть команда импорта XML-схемы: выбираете .xsd, и платформа сама строит пакет с типами.

3. Обойтись без изменения конфигурации. Во внешней обработке фабрику можно собрать прямо из файла схемы:

Фабрика = СоздатьФабрикуXDTO("C:\Schemas\orders.xsd");

Этот приём выручает, когда конфигурация на поддержке и снимать её с замка ради одной выгрузки не хочется.

Как описать типы внутри пакета

В пакете два вида типов:

  • 📦 Тип объекта — составная структура со свойствами (заказ, строка заказа, контрагент);
  • 🔤 Тип значения — простое значение с ограничениями (строка длиной до 12 символов, число с двумя знаками после запятой).

У каждого свойства объекта задайте:

ПараметрЧто значитПример
ТипБазовый тип XML или тип из пакетаxs:string, xs:decimal, xs:date, Строка
Нижняя границаСколько раз свойство обязано встретиться0 — необязательное, 1 — обязательное
Верхняя границаМаксимум повторов1 — одиночное, -1 — список без ограничения
ФормаЭлемент или атрибут XMLЭлемент для данных, Атрибут для служебных полей

Типовая схема для заказа выглядит так: тип Заказ со свойствами Номер, Дата, Контрагент и Строки (верхняя граница -1), а тип Строка — со свойствами Номенклатура, Количество, Сумма. Плюс корневой элемент: свойство пакета Заказы, которое станет корнем файла.

Сразу продумайте нижние границы. Если поле в данных бывает пустым, а в схеме стоит 1, проверка структуры упадёт на первой же такой записи.

Как преобразовать объект 1С в XDTO

Есть два принципиально разных способа. Выбор зависит от того, кто будет читать файл.

СпособКогда подходитФормат файла
ФабрикаXDTO + свой пакетФайл читает чужая система по согласованной схемеВаш, ровно по XSD
СериализаторXDTOФайл загружает другая база 1С с той же конфигурациейВнутренний формат 1С с GUID ссылок

Способ 1. Заполнение объекта по своему пакету

Сначала получаете тип по URI и имени, затем создаёте объект и заполняете свойства. Код выполняется на сервере.

&НаСервере
Функция ЗаказВXDTO(ДокументСсылка)

    URI = "http://example.ru/export/orders";

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

    Заказ = ФабрикаXDTO.Создать(ТипЗаказ);
    Заказ.Номер      = ДокументСсылка.Номер;
    Заказ.Дата       = ДокументСсылка.Дата;
    Заказ.Контрагент = Строка(ДокументСсылка.Контрагент);

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

    Возврат Заказ;

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

Три вещи, на которых чаще всего спотыкаются:

  1. Свойство с верхней границей -1 — это СписокXDTO. Ему не присваивают значение, в него добавляют через Добавить().
  2. Ссылочные поля (Контрагент, Номенклатура) нужно явно привести к строке, коду или ИНН. Ссылку 1С фабрика по чужой схеме не запишет.
  3. Если в пакете задан тип значения с ограничением длины, обрежьте строку заранее через Лев(), иначе объект не пройдёт проверку.

Не называйте переменную для строки заказа Строка. Она перекроет глобальную функцию Строка(), и приведение ссылок к строке в том же цикле сломается. Отсюда имя ЭлементСтроки в примере.

Перед заполнением полезно посмотреть, какие свойства есть у типа: ТипЗаказ.Свойства возвращает их коллекцию с именами, типами и границами. Так проще свериться со схемой, которую прислал контрагент, не открывая конфигуратор.

Способ 2. Сериализация объекта конфигурации

Для обмена между одинаковыми базами пакет писать не нужно. Глобальный СериализаторXDTO превращает справочник, документ или набор записей регистра в XDTO сам:

ОбъектXDTO = СериализаторXDTO.ЗаписатьXDTO(ДокументСсылка.ПолучитьОбъект());

Полученный объект можно разобрать, поправить и только потом записать. А если править нечего, проще писать сразу в файл, это показано в следующем разделе.

Запись XDTO в файл на диске

Сама запись — пять строк. Удобно оформить её отдельной серверной процедурой, которой передаёте объект и путь.

&НаСервере
Процедура ЗаписатьXDTOВФайл(ОбъектXDTO, ПутьКФайлу)

    Параметры = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Истина);

    ЗаписьXML = Новый ЗаписьXML;
    ЗаписьXML.ОткрытьФайл(ПутьКФайлу, Параметры);
    ЗаписьXML.ЗаписатьОбъявлениеXML();

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

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

КонецПроцедуры

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

Для объектов конфигурации без своего пакета вместо строки с фабрикой пишите:

СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ДокументОбъект);

Несколько объектов в одном файле

Если в файл нужно сложить, например, все заказы за день, откройте корневой элемент вручную и пишите объекты внутрь него:

ЗаписьXML.ЗаписатьНачалоЭлемента("Заказы");
ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("", "http://example.ru/export/orders");

Для Каждого Заказ Из СписокЗаказов Цикл
    ФабрикаXDTO.ЗаписатьXML(ЗаписьXML, Заказ);
КонецЦикла;

ЗаписьXML.ЗаписатьКонецЭлемента();

Объявление пространства имён на корне избавляет от его повторения у каждого вложенного элемента.

Где выполнять код и куда попадёт файл

Путь к файлу — это путь на том компьютере, где выполняется код. Отсюда несколько практических следствий:

  • 🖥️ В клиент-серверном варианте код с &НаСервере пишет файл на диск сервера 1С, а не пользователя. Папка должна существовать, а у учётной записи службы сервера должны быть права на запись.
  • 🌐 ФабрикаXDTO недоступна в тонком и веб-клиенте, поэтому формирование XML всегда уходит на сервер.
  • 💾 Чтобы отдать файл пользователю, запишите его во временный файл (ПолучитьИмяВременногоФайла("xml")), поместите двоичные данные во временное хранилище через ПоместитьВоВременноеХранилище(Новый ДвоичныеДанные(Путь)), а на клиенте сохраните по адресу методом НачатьПолучениеФайлаССервера. Временный файл после этого удалите через УдалитьФайлы.

Для отладки не нужен файл вовсе: вызовите ЗаписьXML.УстановитьСтроку() вместо ОткрытьФайл, а ЗаписьXML.Закрыть() вернёт готовый XML строкой. Её удобно посмотреть в отладчике.

Выгрузка XDTO через HTTP-сервис

Когда внешняя система сама забирает данные, файл на диске не нужен: тот же XML можно отдавать по HTTP. Сервис создаётся в ветке Общие → HTTP-сервисы, у него задаётся корневой URL, шаблон адреса и метод GET.

Обработчик метода формирует XML строкой и кладёт его в тело ответа:

Функция ЗаказыGET(Запрос)

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

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

    Возврат Ответ;

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

СобратьЗаказы() — ваша функция, которая возвращает корневой объект XDTO. Параметры фильтра (дату, номер) берите из Запрос.ПараметрыЗапроса или из параметров шаблона URL.

Чтобы сервис был доступен снаружи, базу публикуют на веб-сервере (IIS или Apache) из конфигуратора, отметив HTTP-сервис в диалоге публикации.

Забрать ответ сервиса сразу в файл

Обратная сторона — другая база 1С забирает XML и сохраняет его на диск. Метод Получить у HTTPСоединение умеет писать тело ответа прямо в файл вторым параметром:

Соединение = Новый HTTPСоединение("server.example.ru", 443,,,,, Новый ЗащищенноеСоединениеOpenSSL);
Запрос = Новый HTTPЗапрос("/base/hs/export/orders");
Ответ = Соединение.Получить(Запрос, "D:\Exchange\orders.xml");

Если Ответ.КодСостояния <> 200 Тогда
    ВызватьИсключение "Сервис вернул код " + Формат(Ответ.КодСостояния, "ЧГ=0");
КонецЕсли;

Проверяйте код состояния. При ошибке 500 в файл запишется не XML, а текст ошибки сервера, и следующий шаг обмена прочитает мусор.

Проверка структуры и обработка ошибок XDTO

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

Попытка
    Заказ.Проверить();
    ЗаписатьXDTOВФайл(Заказ, ПутьКФайлу);
Исключение
    ЗаписьЖурналаРегистрации("Выгрузка XDTO",
        УровеньЖурналаРегистрации.Ошибка,,,
        ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
    ВызватьИсключение;
КонецПопытки;

Запись в журнал регистрации обязательна для фоновых выгрузок: иначе ошибку никто не увидит. Смотреть её потом в Администрирование → Обслуживание → Журнал регистрации с отбором по событию «Выгрузка XDTO».

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

Контроль после записи

Для критичных обменов полезно прочитать только что записанный файл обратно. Ошибка формата всплывёт у вас, а не у получателя:

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

Если файл не соответствует типу, ПрочитатьXML вызовет исключение.

Автоматическая выгрузка XDTO в файл по расписанию

Ручная кнопка годится для разовых задач. Регулярный обмен переводят на расписание. Вариантов два.

Регламентное задание

  1. Создайте серверный общий модуль и экспортную процедуру без параметров, например ВыгрузкаЗаказов.ВыполнитьВыгрузку(). Внутри — формирование XDTO, проверка и запись в файл.
  2. В ветке Общие → Регламентные задания добавьте задание, укажите эту процедуру в свойстве «Имя метода», включите флаги «Использование» и «Предопределенное».
  3. Задайте расписание: например, каждый день в 23:00 или каждые 15 минут.
  4. Обновите конфигурацию базы данных.

Имя файла делайте уникальным, иначе каждая выгрузка перезапишет предыдущую:

ИмяФайла = "D:\Exchange\orders_" + Формат(ТекущаяДатаСеанса(), "ДФ=yyyyMMdd_HHmmss") + ".xml";

В файловом варианте регламентные задания выполняются, только пока открыт хотя бы один сеанс базы. Если ночью все вышли из программы, выгрузка в 23:00 не случится. Для файловых баз надёжнее второй способ.

Внешняя обработка и планировщик Windows

Логику выгрузки кладут во внешнюю обработку, а запускают её из командной строки ключом /Execute:

"C:\Program Files\1cv8\8.3.24.1691\bin\1cv8.exe" ENTERPRISE /F"D:\Bases\Trade" /N"Обмен" /P"пароль" /Execute"D:\Exchange\ExportXDTO.epf" /DisableStartupMessages

Номер версии в пути замените на установленный у вас. Обработка выполняет выгрузку в обработчике ПриОткрытии формы и закрывает сеанс через ЗавершитьРаботуСистемы(Ложь). Эту строку ставят в планировщик заданий Windows.

Заведите для обмена отдельного пользователя 1С с минимальными правами: только чтение нужных объектов. Пароль в командной строке виден всем, у кого есть доступ к заданию планировщика, поэтому права этого пользователя лучше урезать.

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

Чем отличается ФабрикаXDTO.ЗаписатьXML от глобального ЗаписатьXML?
Глобальный ЗаписатьXML(ЗаписьXML, Значение) сериализует значения 1С в собственном формате платформы, как СериализаторXDTO. ФабрикаXDTO.ЗаписатьXML пишет объект XDTO по вашей схеме. Для обмена с внешней системой нужен второй.
Можно ли выгрузить XDTO в JSON вместо XML?
Да. Объект XDTO записывается в JSON через ЗаписьJSON и метод ФабрикаXDTO.ЗаписатьJSON. Структура та же, меняется только формат файла.
Как выгрузить XSD-схему из существующего XDTO-пакета?
В конфигураторе в контекстном меню пакета есть команда экспорта XML-схемы. Полученный .xsd отдают получателю как описание формата.
Почему в файле у элементов появились префиксы вида d1p1?
Платформа сама генерирует префиксы для пространств имён, которые не объявлены заранее. Объявите их на корневом элементе через ЗаписатьСоответствиеПространстваИмен — префиксы станут вашими или исчезнут.
Сколько данных можно записать за один вызов?
Объект XDTO целиком строится в памяти сервера. Для десятков тысяч документов пишите их в цикле по одному внутри открытого корневого элемента, а не собирайте один огромный объект.