Как правильно сформировать XML-файл в 1С и избежать ошибки «Ошибочный порядок записи XML»?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Работа с форматом XML — одна из базовых задач интеграции 1С с внешними системами. Но начинающие разработчики часто сталкиваются со специфическими ошибками платформы. Самая популярная из них — «Ошибочный порядок записи XML». Давайте подробно разберем, почему возникает эта ошибка, как исправить структуру вашего XML-документа, сделать код читаемым и какие альтернативные (более современные) подходы к формированию XML существуют в платформе 1С:Предприятие.

Выясняем причину ошибки: золотое правило XML

Рассмотрим ситуацию, с которой столкнулся автор темы. В коде выполняется обход таблицы данных в цикле, и для каждой строки создается элемент contract_status с вложенными тегами. Программа успешно записывает первую строку таблицы, но при попытке записать вторую — аварийно завершает работу с системной ошибкой.

Причина этого кроется в фундаментальном правиле спецификации XML: любой корректный XML-документ должен иметь строго один корневой (root) элемент. Внутри этого корневого элемента может находиться сколько угодно дочерних узлов, но на самом верхнем уровне вложенности дублирование тегов недопустимо.

Давайте проанализируем исходный (проблемный) код автора:


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

Для Каждого Стр Из ТаблицаДанных Цикл
    // Платформа пытается создать новый корневой элемент на каждой итерации!
    ЗаписьXML.ЗаписатьНачалоЭлемента("contract_status"); 
    
    ЗаписьXML.ЗаписатьНачалоЭлемента("syncdate");
    ЗаписьXML.ЗаписатьТекст(ПреобразоватьДатуВФорматSOLVO(ТекущаяДата));
    ЗаписьXML.ЗаписатьКонецЭлемента();
    
    ЗаписьXML.ЗаписатьНачалоЭлемента("contract");
    ЗаписьXML.ЗаписатьТекст(Стр.ИДДоговора);
    ЗаписьXML.ЗаписатьКонецЭлемента();
    
    ЗаписьXML.ЗаписатьНачалоЭлемента("validate_status");
    ЗаписьXML.ЗаписатьТекст("true");
    ЗаписьXML.ЗаписатьКонецЭлемента();
    
    ЗаписьXML.ЗаписатьНачалоЭлемента("comment");
    ЗаписьXML.ЗаписатьТекст("Недостаточно средств");
    ЗаписьXML.ЗаписатьКонецЭлемента();
    
    ЗаписьXML.ЗаписатьНачалоЭлемента("action_date");
    ЗаписьXML.ЗаписатьТекст(ПреобразоватьДатуВФорматSOLVO(ТекущаяДата));
    ЗаписьXML.ЗаписатьКонецЭлемента();
    
    ЗаписьXML.ЗаписатьКонецЭлемента(); // Закрываем contract_status
КонецЦикла;

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

На первой итерации цикла создается элемент contract_status. Для 1С он автоматически становится корневым. На второй итерации метод ЗаписатьНачалоЭлемента("contract_status") пытается создать еще один элемент верхнего уровня. Платформа видит нарушение структуры XML-документа и моментально генерирует исключение.

Решение 1. Добавление общего корневого элемента

Самый простой и логичный способ исправить эту ошибку — обернуть все циклические записи в один общий родительский тег. Давайте назовем его, например, contracts_data.

Для этого нам нужно открыть корневой элемент до начала цикла и закрыть его сразу после завершения цикла. Перепишем наш код правильно:


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

// ШАГ 1. Открываем единый корневой элемент ДО цикла
ЗаписьXML.ЗаписатьНачалоЭлемента("contracts_data");

Для Каждого Стр Из ТаблицаДанных Цикл
    // Теперь contract_status — это вложенный (дочерний) элемент
    ЗаписьXML.ЗаписатьНачалоЭлемента("contract_status"); 
    
    ЗаписьXML.ЗаписатьНачалоЭлемента("syncdate");
    ЗаписьXML.ЗаписатьТекст(ПреобразоватьДатуВФорматSOLVO(ТекущаяДата));
    ЗаписьXML.ЗаписатьКонецЭлемента();
    
    ЗаписьXML.ЗаписатьНачалоЭлемента("contract");
    ЗаписьXML.ЗаписатьТекст(Стр.ИДДоговора);
    ЗаписьXML.ЗаписатьКонецЭлемента();
    
    ЗаписьXML.ЗаписатьНачалоЭлемента("validate_status");
    ЗаписьXML.ЗаписатьТекст("true");
    ЗаписьXML.ЗаписатьКонецЭлемента();
    
    ЗаписьXML.ЗаписатьНачалоЭлемента("comment");
    ЗаписьXML.ЗаписатьТекст("Недостаточно средств");
    ЗаписьXML.ЗаписатьКонецЭлемента();
    
    ЗаписьXML.ЗаписатьНачалоЭлемента("action_date");
    ЗаписьXML.ЗаписатьТекст(ПреобразоватьДатуВФорматSOLVO(ТекущаяДата));
    ЗаписьXML.ЗаписатьКонецЭлемента();
    
    ЗаписьXML.ЗаписатьКонецЭлемента(); // Закрываем contract_status
КонецЦикла;

// ШАГ 2. Закрываем корневой элемент ПОСЛЕ цикла
ЗаписьXML.ЗаписатьКонецЭлемента(); // Закрываем contracts_data

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

Теперь структура документа будет полностью соответствовать международным стандартам XML. Ошибка «Ошибочный порядок записи» гарантированно исчезнет.

Решение 2. Форматирование XML («Чтоб не в одну кучу»)

При стандартном открытии файла через ЗаписьXML.ОткрытьФайл() платформа записывает данные сплошным потоком без переносов строк и отступов. Это минимизирует размер файла, но делает его абсолютно нечитаемым для человека. На форуме автор пожаловался, что «всё пишется в одну кучу».

Чтобы получить красивое дерево XML с отступами (форматированием), нам нужно использовать специальный объект — ПараметрыЗаписиXML. В его конструкторе третьим параметром передается булево значение, отвечающее за перенос строк и табуляцию.

Давайте посмотрим, как применить это на практике:


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

// Создаем параметры записи: Кодировка, Версия, ИспользоватьОтступы (Истина)
ПараметрыНастройки = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Истина);

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

// Далее идет наш стандартный код записи...

После этого XML-файл примет красивый, структурированный вид с понятной иерархией тегов.

Решение 3. Современный подход через XDTO (Рекомендуемый способ)

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

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

Рассмотрим по шагам, как выгрузить данные с помощью XDTO:

  1. Создайте в конфигурации XDTO-пакет, соответствующий схеме принимающей стороны (или загрузите динамически схему .xsd).
  2. Опишите типы данных для contracts_data и вложенного элемента contract_status.
  3. В коде заполняйте объекты XDTO программно, как обычные структуры:

// Создаем объект корневого типа на базе фабрики XDTO
ТипКорня = ФабрикаXDTO.Тип("http://www.yourdomain.com/contracts", "contracts_data");
КорневойОбъект = ФабрикаXDTO.Создать(ТипКорня);

ТипЭлемента = ФабрикаXDTO.Тип("http://www.yourdomain.com/contracts", "contract_status");

Для Каждого Стр Из ТаблицаДанных Цикл
    // Создаем подчиненный объект
    НовыйСтатус =  ФабрикаXDTO.Создать(ТипЭлемента);
    НовыйСтатус.syncdate = ТекущаяДата();
    НовыйСтатус.contract = Стр.ИДДоговора;
    НовыйСтатус.validate_status = Истина;
    НовыйСтатус.comment = "Недостаточно средств";
    НовыйСтатус.action_date = ТекущаяДата();
    
    // Добавляем объект в список корневого элемента
    КорневойОбъект.contract_status.Добавить(НовыйСтатус);
КонецЦикла;

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

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

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

При использовании XDTO платформа сама следит за валидностью тегов, правильным порядком их закрытия и корректно преобразует типы данных (например, даты будут автоматически записаны по стандарту ISO 8601, без необходимости писать собственные функции преобразования формата).

Решение 4. Альтернативный объектный подход через DOM

Если XDTO-схемы у вас нет, а писать XML последовательно все еще не хочется, отличным промежуточным решением является использование объектной модели документа — DOM (Document Object Model). При этом подходе структура документа выстраивается в оперативной памяти компьютера в виде дерева объектов, а затем выгружается на диск.

Давайте разберем практический пример реализации DOM в 1С:


// Создаем пустой DOM-документ
ДокументDOM = Новый ДокументDOM;

// Создаем корневой элемент и добавляем его в документ
КорневойЭлемент = ДокументDOM.СоздатьЭлемент("contracts_data");
ДокументDOM.ДобавитьДочерний(КорневойЭлемент);

Для Каждого Стр Из ТаблицаДанных Цикл
    // Создаем элемент статуса договора
    ЭлементСтатус = ДокументDOM.СоздатьЭлемент("contract_status");
    КорневойЭлемент.ДобавитьДочерний(ЭлементСтатус);
    
    // Вложенный элемент: syncdate
    ЭлементДата = ДокументDOM.СоздатьЭлемент("syncdate");
    ЭлементДата.ТекстовоеСодержимое = Формат(ТекущаяДата(), "ДФ=yyyy-MM-ddTHH:mm:ss");
    ЭлементСтатус.ДобавитьДочерний(ЭлементДата);
    
    // Вложенный элемент: contract
    ЭлементКонтракт = ДокументDOM.СоздатьЭлемент("contract");
    ЭлементКонтракт.ТекстовоеСодержимое = Стр.ИДДоговора;
    ЭлементСтатус.ДобавитьДочерний(ЭлементКонтракт);
    
    // Вложенный элемент: validate_status
    ЭлементВалидность = ДокументDOM.СоздатьЭлемент("validate_status");
    ЭлементВалидность.ТекстовоеСодержимое = "true";
    ЭлементСтатус.ДобавитьДочерний(ЭлементВалидность);
КонецЦикла;

// Выполняем запись DOM в файл на диске
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ПутьКФайлуДляЗаписи, Новый ПараметрыЗаписиXML("UTF-8", "1.0", Истина));

ЗаписьDOM = Новый ЗаписьDOM;
ЗаписьDOM.Записать(ДокументDOM, ЗаписьXML);

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

Этот способ исключает ошибки ручной записи тегов, так как вы оперируете понятными объектами платформы 1С. Метод Записать объекта ЗаписьDOM самостоятельно сформирует корректный XML-файл.

Подведем итоги

Мы подробно разобрали, почему возникает ошибка нарушенного порядка записи XML в 1С, и рассмотрели четыре различных способа решения этой проблемы. Для простых и быстрых выгрузок отлично подойдет ручная запись через ЗаписьXML с добавлением единого корневого элемента и использованием ПараметрыЗаписиXML для красивого форматирования. Для масштабных проектов и интеграций со строгими требованиями к форматам данных мы рекомендуем использовать механизмы XDTO или DOM.

← На главную