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

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

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

Разберем детально, почему возникает данная ошибка, как устроен механизм потоковой записи XML в платформе 1С:Предприятие и как правильно организовать структуру кода.

Причины возникновения ошибки

Основная причина появления ошибки заключается в нарушении спецификации стандарта XML и логики работы потокового объекта ЗаписьXML. Выделим ключевые факторы:

  1. Отсутствие единого корневого элемента: Согласно стандарту XML, корректный документ обязан содержать строго один корневой узел (root element). Если мы пытаемся записать несколько узлов документов верхнего уровня подряд без объединяющего корня, второй вызов ЗаписатьНачалоЭлемента() на верхнем уровне вызовет ошибку, так как после закрытия первого корневого тега документ считается завершенным.
  2. Преждевременный вызов метода Закрыть(): Если метод ЗаписьXML.Закрыть() вызывается внутри процедуры обработки отдельного документа, то при переходе к следующему объекту поток уже закрыт, и любая запись в него невозможна.
  3. Нарушение баланса тегов: Непарное количество вызовов методов ЗаписатьНачалоЭлемента() и ЗаписатьКонецЭлемента() (в том числе во вложенных вспомогательных процедурах сериализации) нарушает внутренний стек тегов.

Пошаговое решение: создание единого корневого узла

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

Посмотрим на пример управляющей процедуры, которая инициализирует XML и управляет процессом:


Процедура ВыгрузитьДокументыВXML(МассивДокументов, ПутьКФайлу)
    
    ЗаписьXML = Новый ЗаписьXML;
    ПараметрыЗаписи = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Ложь);
    ЗаписьXML.ОткрытьФайл(ПутьКФайлу, ПараметрыЗаписи);
    
    // 1. Открываем единый корневой элемент файла
    ЗаписьXML.ЗаписатьНачалоЭлемента("ФайлОбмена");
    
    // 2. В цикле выгружаем каждый документ как дочерний элемент корня
    Для Каждого ТекущийДокумент Из МассивДокументов Цикл
        ВыгрузитьОдинДокумент(ЗаписьXML, ТекущийДокумент);
    КонецЦикла;
    
    // 3. Закрываем корневой элемент
    ЗаписьXML.ЗаписатьКонецЭлемента();
    
    // 4. Завершаем работу с файлом
    ЗаписьXML.Закрыть();
    
КонецПроцедуры

Теперь проанализируем процедуру выгрузки единичного документа. Обратим внимание, что она не должна содержать вызов ЗаписьXML.Закрыть():


Процедура ВыгрузитьОдинДокумент(ЗаписьXML, Данные)
    
    // Открываем узел конкретного документа
    ЗаписьXML.ЗаписатьНачалоЭлемента("DocumentObject.ПоступлениеТоваровУслуг.Вручную");
    
    ЗаписатьXML(ЗаписьXML, Данные.Ссылка, "Ref", НазначениеТипаXML.Явное);
    ЗаписатьXML(ЗаписьXML, Данные.Номер, "Номер", НазначениеТипаXML.Явное);
    ЗаписатьXML(ЗаписьXML, Данные.Дата, "Дата", НазначениеТипаXML.Явное);
    ЗаписатьXML(ЗаписьXML, Данные.СуммаДокумента, "СуммаДокумента", НазначениеТипаXML.Явное);
    
    // Выгрузка табличной части
    ТЧ = Данные.Товары.Выгрузить();
    Для Каждого СтрокаТЧ Из ТЧ Цикл
        ЗаписьXML.ЗаписатьНачалоЭлемента("DocumentTabularSectionRow.ПоступлениеТоваровУслуг.Товары.Вручную");
        ЗаписатьXML(ЗаписьXML, СтрокаТЧ.Номенклатура, "Номенклатура", НазначениеТипаXML.Явное);
        ЗаписатьXML(ЗаписьXML, СтрокаТЧ.Количество, "Количество", НазначениеТипаXML.Явное);
        ЗаписатьXML(ЗаписьXML, СтрокаТЧ.Сумма, "Сумма", НазначениеТипаXML.Явное);
        ЗаписьXML.ЗаписатьКонецЭлемента(); // Закрываем строку ТЧ
    КонецЦикла;
    
    // Закрываем узел текущего документа
    ЗаписьXML.ЗаписатьКонецЭлемента();
    
КонецПроцедуры

Правила контроля стека элементов

Объект ЗаписьXML работает по принципу потоковой однонаправленной записи. Чтобы избежать ошибок порядка записи, придерживаемся следующих правил:

  1. Соблюдаем строгую парность методов: На каждый вызов ЗаписатьНачалоЭлемента() должен строго приходиться один вызов ЗаписатьКонецЭлемента().
  2. Проверяем вложенные методы: Если внутри выгрузки вызываются сторонние функции (например, сериализация договоров или контрагентов), убедимся, что они закрывают все порожденные ими теги до возврата управления.
  3. Используем безопасное закрытие потока: Оборачиваем формирование файла в конструкцию Попытка ... Исключение, чтобы в случае ошибки выполнения поток ЗаписьXML не оставался заблокированным в операционной системе.

Альтернативные способы формирования структуры

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

  1. Механизм XDTO (СериализаторXDTO / ФабрикаXDTO): Автоматически формирует корректную XML-структуру на основе метаданных или схемы XDTO, исключая человеческий фактор при ручном открытии и закрытии узлов.
  2. Объектная модель DOM (ДокументDOM): Позволяет формировать дерево XML в памяти и манипулировать узлами без риска нарушить линейную последовательность записи тегов.
← На главную