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

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

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

Разбор причины ошибки: иерархия тегов

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

Рассмотрим исправленный алгоритм работы внутри цикла:


// Перед циклом обязательно открываем корневой элемент
Файл.ЗаписатьНачалоЭлемента("ТаблСчФакт");

Для каждого СтрДанных Из ЭкземплярДанныхДляПечати.ТабличнаяЧасть Цикл
    НомерСтроки = НомерСтроки + 1;
    
    // Открываем тег строки товара
    Файл.ЗаписатьНачалоЭлемента("СведТов");
    
    // Записываем атрибуты СРАЗУ после открытия элемента
    Файл.ЗаписатьАтрибут("НомСтр", Строка(НомерСтроки));
    Файл.ЗаписатьАтрибут("НаимТов", Строка(СтрДанных.Товар));
    Файл.ЗаписатьАтрибут("ОКЕИ_Тов", Строка(СтрДанных.ЕдиницаИзмеренияКод));
    Файл.ЗаписатьАтрибут("КолТов", Формат(СтрДанных.Количество, "ЧГ=0; ЧРД=."));
    
    // Закрываем тег строки товара (только один раз!)
    Файл.ЗаписатьКонецЭлемента(); 
КонецЦикла;

// Закрываем корневой элемент после завершения цикла
Файл.ЗаписатьКонецЭлемента(); 

Важный момент: если вы вызываете ЗаписатьКонецЭлемента() больше раз, чем было вызвано ЗаписатьНачалоЭлемента(), платформа выбросит исключение, так как ей «нечего закрывать».

Золотые правила работы с ЗаписьXML

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

  1. Объявление XML: Метод ЗаписатьОбъявлениеXML() должен вызываться первым, сразу после открытия файла. Это добавит в начало файла строку <?xml version="1.0" encoding="UTF-8"?>.
  2. Корневой элемент: Любой корректный XML должен содержать один корневой элемент. Если вы начнете писать данные без вызова ЗаписатьНачалоЭлемента() для корня, структура будет нарушена.
  3. Атрибуты: Метод ЗаписатьАтрибут() можно вызывать только непосредственно после ЗаписатьНачалоЭлемента(). Если вы уже записали вложенный элемент или текст с помощью ЗаписатьТекст(), добавить атрибут к текущему узлу уже не получится.
  4. Закрытие тегов: Следите за парностью вызовов. Хорошей практикой считается использование отступов в коде, которые визуально повторяют вложенность тегов XML.

Проблема форматирования данных

В примере автора используется функция Строка() и Формат() для чисел. Проанализируем ситуацию: стандартное преобразование числа в строку в 1С зависит от региональных настроек сервера или клиента. Если в настройках разделителем дробной части стоит запятая, а разделителем групп разрядов — неразрывный пробел, то XML получится невалидным (например, 1 000,50 вместо 1000.50).

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

Формат(Сумма, "ЧГ=0; ЧРД=.")

Где ЧГ=0 убирает группировку разрядов, а ЧРД=. принудительно ставит точку.

Альтернативный метод: Сериализация через XDTO

Если вам нужно выгрузить объект целиком и вы не хотите вручную прописывать каждый тег, рассмотрим использование механизма XDTO. Это гораздо более надежный способ, который берет на себя контроль за порядком записи тегов. Выясним, как это работает на примере:


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

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

Использование объектной модели DOM

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


ДокDOM = Новый ДокументDOM;
КорневойУзел = ДокDOM.СоздатьЭлемент("Данные");
ДокDOM.ДобавитьПодчиненный(КорневойУзел);

Для каждого Стр Из ТаблицаДанных Цикл
    УзелТовар = ДокDOM.СоздатьЭлемент("Товар");
    УзелТовар.УстановитьАтрибут("Название", Стр.Наименование);
    // Добавляем узел в дерево
    КорневойУзел.ДобавитьПодчиненный(УзелТовар);
КонецЦикла;

// Теперь записываем всё дерево в файл
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ПутьКФайлу);
ЗаписьDOM = Новый ЗаписьDOM;
ЗаписьDOM.Записать(ДокDOM, ЗаписьXML);
ЗаписьXML.Закрыть();

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

Резюме

Для исправления ошибки «Ошибочный порядок записи XML» выполните следующие действия:

  1. Проверьте количество вызовов ЗаписатьНачалоЭлемента и ЗаписатьКонецЭлемента — они должны строго совпадать.
  2. Убедитесь, что все вызовы ЗаписатьАтрибут идут сразу после открытия тега.
  3. Проверьте наличие корневого элемента, в который вложены все остальные узлы.
  4. Используйте правильное форматирование чисел (точка вместо запятой) для валидности файла.
← На главную