Выгрузка данных в XML-файл средствами встроенного языка 1С 8.3

· 10 мин

Содержание

Чтобы сохранить XML в файл в 1С, создайте объект ЗаписьXML, откройте файл методом ОткрытьФайл(ИмяФайла, "UTF-8"), запишите объявление, элементы и атрибуты и обязательно вызовите Закрыть(). Если нужно выгрузить объект базы целиком (документ, элемент справочника, таблицу значений), вместо ручной разметки передайте его в СериализаторXDTO.ЗаписатьXML() — платформа сама построит XML.

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

Что подготовить до написания кода

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

Решите три вопроса:

  • 📁 Где окажется файл. Код в модуле с директивой &НаСервере пишет на диск сервера 1С. Пользователь клиент-серверной базы этот файл не увидит.
  • 🔤 Какая кодировка. По умолчанию UTF-8. Старые учётные системы иногда ждут windows-1251.
  • 🧩 Вручную или сериализацией. Чужой формат — только вручную через ЗаписьXML. Обмен между базами 1С с одинаковыми объектами — проще через XDTO.
СпособКогда подходитОграничения
ЗаписьXML вручнуюФормат задан получателем, нужен полный контроль над тегамиБольше кода, баланс начала и конца элементов на вас
СериализаторXDTOОбмен 1С ↔ 1С, бэкап отдельных объектов, отладкаСтруктура и имена тегов задаются платформой
Обработка «Выгрузка и загрузка данных XML»Разовая выгрузка без программированияТолько для обмена между базами с одинаковой конфигурацией

Ручная запись XML в файл через ЗаписьXML

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

Порядок вызовов

  1. Новый ЗаписьXML — создать писатель.
  2. ОткрытьФайл(...) — указать путь и кодировку (или объект ПараметрыЗаписиXML).
  3. ЗаписатьОбъявлениеXML() — строка <?xml version="1.0" encoding="UTF-8"?>. Вызывается первой.
  4. ЗаписатьНачалоЭлемента("Имя") — открыть тег.
  5. ЗаписатьАтрибут("Имя", Значение) — атрибуты пишутся сразу после начала элемента, до текста и вложенных тегов.
  6. ЗаписатьТекст(Строка) — содержимое.
  7. ЗаписатьКонецЭлемента() — закрыть тег. Каждому началу — свой конец.
  8. Закрыть() — сбросить буфер на диск и освободить файл.

Пример: выгрузка номенклатуры

&НаСервере
Процедура ВыгрузитьНоменклатуруВXML(ИмяФайла)

    Параметры = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Истина); // Истина — с отступами
    Запись = Новый ЗаписьXML;
    Запись.ОткрытьФайл(ИмяФайла, Параметры);
    Запись.ЗаписатьОбъявлениеXML();

    Запись.ЗаписатьНачалоЭлемента("Каталог");
    Запись.ЗаписатьАтрибут("Дата", XMLСтрока(ТекущаяДатаСеанса()));

    Запрос = Новый Запрос;
    Запрос.Текст =
    "ВЫБРАТЬ
    |   Номенклатура.Ссылка КАК Ссылка,
    |   Номенклатура.Код КАК Код,
    |   Номенклатура.Наименование КАК Наименование
    |ИЗ
    |   Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |   НЕ Номенклатура.ЭтоГруппа
    |   И НЕ Номенклатура.ПометкаУдаления";
    Выборка = Запрос.Выполнить().Выбрать();

    Пока Выборка.Следующий() Цикл
        Запись.ЗаписатьНачалоЭлемента("Товар");
        Запись.ЗаписатьАтрибут("Ид", XMLСтрока(Выборка.Ссылка));
        ЗаписатьПоле(Запись, "Код", СокрЛП(Выборка.Код));
        ЗаписатьПоле(Запись, "Наименование", Выборка.Наименование);
        Запись.ЗаписатьКонецЭлемента(); // Товар
    КонецЦикла;

    Запись.ЗаписатьКонецЭлемента(); // Каталог
    Запись.Закрыть();

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

&НаСервере
Процедура ЗаписатьПоле(Запись, ИмяЭлемента, Значение)
    Запись.ЗаписатьНачалоЭлемента(ИмяЭлемента);
    Запись.ЗаписатьТекст(Значение);
    Запись.ЗаписатьКонецЭлемента();
КонецПроцедуры

На выходе получится файл такого вида:

<?xml version="1.0" encoding="UTF-8"?>
<Каталог Дата="2026-10-07T14:05:12">
	<Товар Ид="5f1c2a90-3b7e-11ef-9c3a-00155d0a1f02">
		<Код>00-00000017</Код>
		<Наименование>Бумага офисная А4</Наименование>
	</Товар>
</Каталог>

Даты, числа, булевы значения и ссылки переводите в текст функцией XMLСтрока(), а не Строка(). Строка(1250.5) даст 1 250,5 с пробелом и запятой — внешняя программа такое число не разберёт. XMLСтрока(1250.5) вернёт 1250.5, дата превратится в 2026-10-07T14:05:12, ссылка — в уникальный идентификатор.

Пространства имён и префиксы

Если получатель требует теги с префиксом, объявите пространство имён сразу после открытия корневого элемента:

Запись.ЗаписатьНачалоЭлемента("Документ", "urn:example:invoice");
Запись.ЗаписатьСоответствиеПространстваИмен("inv", "urn:example:invoice");

Дальше все элементы, открытые с тем же URI вторым параметром, получат префикс inv:.

Сохранение в строку вместо файла

Иногда XML нужен не на диске, а в переменной: для отправки в HTTP-запросе или записи в реквизит. Тогда вместо ОткрытьФайл вызовите Запись.УстановитьСтроку("UTF-8"). Метод Закрыть() в этом случае вернёт готовый текст. Сохранить его в файл потом можно через ЗаписьТекста или Новый ТекстовыйДокумент с методом Записать.

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

Когда нужно выгрузить в XML документ или справочник целиком, со всеми реквизитами и табличными частями, писать каждый тег руками бессмысленно. Глобальный объект СериализаторXDTO делает это одной строкой.

&НаСервере
Процедура ВыгрузитьКонтрагентов(ИмяФайла)

    Запись = Новый ЗаписьXML;
    Запись.ОткрытьФайл(ИмяФайла, "UTF-8");
    Запись.ЗаписатьОбъявлениеXML();
    Запись.ЗаписатьНачалоЭлемента("Данные");
    Запись.ЗаписатьСоответствиеПространстваИмен("xs", "http://www.w3.org/2001/XMLSchema");
    Запись.ЗаписатьСоответствиеПространстваИмен("xsi", "http://www.w3.org/2001/XMLSchema-instance");

    Выборка = Справочники.Контрагенты.Выбрать();
    Пока Выборка.Следующий() Цикл
        Объект = Выборка.ПолучитьОбъект();
        СериализаторXDTO.ЗаписатьXML(Запись, Объект, НазначениеТипаXML.Явное);
    КонецЦикла;

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

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

Объявление префиксов xs и xsi на корневом элементе не обязательно, но без него платформа повторит их в каждом вложенном объекте, и файл распухнет.

Что ещё умеет сериализатор:

  • 📋 Таблицы значений. СериализаторXDTO.ЗаписатьXML(Запись, ТаблицаЗначений) — удобно, чтобы сохранить результат запроса и загрузить его в другой базе без пересборки.
  • 🗂 Наборы записей регистров — как и объекты, пишутся целиком вместе с отбором.
  • 🔁 Обратное чтение. СериализаторXDTO.ПрочитатьXML(Чтение) восстанавливает значение исходного типа.

Ссылки в сериализованном XML записываются как уникальные идентификаторы. Если в базе-приёмнике нет объекта с тем же идентификатором, после загрузки на его месте окажется «битая» ссылка <Объект не найден>. Выгружайте связанные справочники вместе с документами.

Чтение обратно для проверки

Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ИмяФайла);
Чтение.Прочитать(); // встали на корневой элемент «Данные»
Чтение.Прочитать(); // перешли к первому объекту
Пока СериализаторXDTO.ВозможностьЧтенияXML(Чтение) Цикл
    Объект = СериализаторXDTO.ПрочитатьXML(Чтение);
    // здесь можно сравнить реквизиты или записать объект
КонецЦикла;
Чтение.Закрыть();

Для разовой выгрузки без кода есть универсальная обработка «Выгрузка и загрузка данных XML». Она работает на том же механизме: отметили объекты, указали файл, нажали «Выгрузить». Применяют её для переноса справочников между базами одной конфигурации.

Как передать файл с сервера на компьютер пользователя

Самая частая жалоба: «код отработал, а файла нет». В клиент-серверной базе путь C:\Выгрузка\price.xml в серверной процедуре означает диск сервера 1С. В файловой базе в тонком клиенте серверный код тоже может работать на другой машине, если база опубликована на веб-сервере.

Правильная схема — записать во временный файл на сервере, положить двоичные данные во временное хранилище и отдать пользователю с клиента.

&НаКлиенте
Процедура ВыгрузитьВXML(Команда)
    Адрес = СформироватьФайлНаСервере();
    ФайловаяСистемаКлиент.СохранитьФайл(Неопределено, Адрес, "catalog.xml");
КонецПроцедуры

&НаСервере
Функция СформироватьФайлНаСервере()
    ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xml");
    ВыгрузитьНоменклатуруВXML(ИмяВременногоФайла);
    Данные = Новый ДвоичныеДанные(ИмяВременногоФайла);
    УдалитьФайлы(ИмяВременногоФайла);
    Возврат ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор);
КонецФункции

ФайловаяСистемаКлиент.СохранитьФайл — процедура из Библиотеки стандартных подсистем. Она есть в типовых конфигурациях: БП 3.0, ЗУП 3.1, УТ 11. Пользователь увидит обычный диалог «Сохранить как».

В самописной конфигурации без БСП подойдёт платформенный метод ПолучитьФайл(Адрес, "catalog.xml", Истина). Он синхронный: если в свойствах конфигурации запрещены синхронные вызовы, используйте асинхронный вариант НачатьПолучениеФайлов.

Не удаляйте временный файл до чтения в ДвоичныеДанные и не забывайте удалить его после. На сервере с десятками пользователей забытые временные файлы за месяц занимают гигабайты.

Если сохраняете прямо в каталог

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

Каталог = Новый Файл("\\fileserver\exchange\");
Если Не Каталог.Существует() Тогда
    СоздатьКаталог("\\fileserver\exchange\");
КонецЕсли;

Учтите: на сервере 1С код выполняется от имени учётной записи службы (по умолчанию USR1CV8). У неё должны быть права на запись в эту сетевую папку, а не у пользователя, который нажал кнопку.

Выгрузка табличного документа в XML

Отчёт или печатная форма в 1С — это ТабличныйДокумент. Команда сохранения в интерфейсе предлагает MXL, XLSX, PDF, HTML, DOCX и другие форматы, но обычного XML с вашей структурой среди них нет. Поэтому ячейки обходят кодом и записывают через ЗаписьXML.

Пример: первая строка документа — заголовки колонок, дальше данные.

&НаСервере
Процедура ТабличныйДокументВXML(ТабДок, ИмяФайла)

    Запись = Новый ЗаписьXML;
    Запись.ОткрытьФайл(ИмяФайла, Новый ПараметрыЗаписиXML("UTF-8", "1.0", Истина));
    Запись.ЗаписатьОбъявлениеXML();
    Запись.ЗаписатьНачалоЭлемента("Таблица");

    Ширина = ТабДок.ШиринаТаблицы;
    Заголовки = Новый Массив;
    Для НомерКолонки = 1 По Ширина Цикл
        Заголовки.Добавить(ТабДок.Область(1, НомерКолонки, 1, НомерКолонки).Текст);
    КонецЦикла;

    Для НомерСтроки = 2 По ТабДок.ВысотаТаблицы Цикл
        Запись.ЗаписатьНачалоЭлемента("Строка");
        Для НомерКолонки = 1 По Ширина Цикл
            Запись.ЗаписатьНачалоЭлемента("Ячейка");
            Запись.ЗаписатьАтрибут("Колонка", Заголовки[НомерКолонки - 1]);
            Запись.ЗаписатьТекст(ТабДок.Область(НомерСтроки, НомерКолонки, НомерСтроки, НомерКолонки).Текст);
            Запись.ЗаписатьКонецЭлемента();
        КонецЦикла;
        Запись.ЗаписатьКонецЭлемента();
    КонецЦикла;

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

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

Индекс массива сдвинут на единицу: колонки нумеруются с 1, элементы массива — с 0.

Заголовки колонок вынесены в атрибут, а не в имя тега. Имя элемента XML не может содержать пробелы и начинаться с цифры, а «Сумма с НДС» или «1 квартал» — обычные заголовки отчётов.

Если исходные данные приходят из запроса, выгружайте их напрямую из выборки, а не из готового отчёта. В ячейках табличного документа числа уже отформатированы: 1 250,50 вместо 1250.5, и для XML их придётся разбирать обратно.

Кодировка, BOM и спецсимволы

Какую кодировку выбрать

КодировкаСтрока в кодеКогда нужна
UTF-8"UTF-8"По умолчанию, для веб-сервисов, ЭДО, большинства систем
Windows-1251"windows-1251"Старые программы, которые не читают Юникод
UTF-16"UTF-16"Редко, только по прямому требованию получателя

Строка объявления encoding="…" формируется автоматически по кодировке, которую вы передали в ОткрытьФайл. Вписывать её вручную через ЗаписатьБезОбработки не нужно: получится расхождение между объявлением и реальными байтами, и кириллица превратится в «кракозябры».

Отдельная история — метка порядка байтов (BOM) в начале UTF-8-файла. Часть внешних парсеров на ней спотыкается. У ОткрытьФайл есть третий параметр, который отвечает за запись этой сигнатуры: передайте Ложь, если получатель требует файл без BOM.

Спецсимволы

Символы <, >, & и кавычки в тексте и атрибутах ЗаписьXML экранирует сам. Наименование «ООО “Рога & Копыта”» запишется корректно, ничего заменять не надо.

Проблема в другом — управляющие символы с кодами от 0 до 31. Они попадают в базу при вставке из PDF или из чужих программ. XML 1.0 их не допускает (кроме табуляции, перевода строки и возврата каретки), и файл потом не прочитает ни 1С, ни внешний парсер. Перед записью почистите строку:

Функция ОчиститьДляXML(Знач Текст)
    Для Код = 0 По 31 Цикл
        Если Код = 9 Или Код = 10 Или Код = 13 Тогда
            Продолжить;
        КонецЕсли;
        Текст = СтрЗаменить(Текст, Символ(Код), "");
    КонецЦикла;
    Возврат Текст;
КонецФункции

Если в поле лежит HTML-фрагмент или текст с разметкой, который надо сохранить как есть, используйте ЗаписатьСекциюCDATA(Текст). Только помните: внутри CDATA не может встречаться последовательность ]]>.

Ошибки при сохранении XML и проверка готового файла

Перехват ошибок

Оберните запись в Попытка … Исключение и обязательно закройте файл в обеих ветках. Иначе после ошибки он останется занят процессом 1С, и повторная выгрузка упадёт уже на открытии.

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

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

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

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

  1. Размер. Новый Файл(ИмяФайла).Размер() больше нуля — минимальная проверка, что запись дошла до диска.
  2. Корректность разметки. Прочитайте файл целиком через ЧтениеXML. Если разметка битая, метод Прочитать() вызовет исключение с номером строки:
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ИмяФайла);
Пока Чтение.Прочитать() Цикл
КонецЦикла;
Чтение.Закрыть();
  1. Соответствие формату. Если у получателя есть XSD-схема, загрузите её в XDTO-пакет конфигурации и формируйте данные через ФабрикаXDTO: значения, не подходящие под тип, вызовут ошибку уже при заполнении объекта. Для разовой проверки достаточно открыть файл в любом XML-редакторе с валидацией по схеме.
  2. Глазами. Откройте файл в браузере: он покажет дерево элементов или строку, где ломается разметка.

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

Чем ЗаписьXML отличается от ЗаписьДокументаDOM?
ЗаписьXML пишет поток последовательно и почти не тратит память. DOM сначала строит весь документ в памяти, зато позволяет править узлы в любом порядке. Для выгрузки больших объёмов выбирайте ЗаписьXML.
Можно ли дописать данные в уже существующий XML-файл?
Нет, ЗаписьXML всегда создаёт файл заново. Чтобы добавить элементы, прочитайте старый файл и запишите новый целиком, либо соберите документ через DOM и сохраните его.
Как записать XML без отступов и переносов строк?
Создайте ПараметрыЗаписиXML с третьим параметром Ложь или вызовите ОткрытьФайл только с кодировкой. Файл получится в одну строку и станет меньше.
Как выгрузить XML из регламентного задания?
Так же, как с сервера: сразу пишите в сетевую папку по полному пути. Права на запись должны быть у учётной записи, под которой работает служба сервера 1С.
Как в XML выглядят пустая дата и булево значение?
XMLСтрока(Ложь) возвращает false, Истина — true. Пустая дата превращается в 0001-01-01T00:00:00. Если получатель ждёт пустой тег, проверяйте значение и пишите пустую строку сами.