Выгрузка документов и справочников в формат XML — одна из самых частых задач при интеграции 1С с внешними информационными системами. Начинающие разработчики часто сталкиваются с техническими трудностями на этом пути: нарушается иерархия элементов, XML-файл записывается некорректно, либо возникают сложные ошибки отображения типов данных (особенно ссылочных, таких как СправочникСсылка). В этой статье мы подробно разберем типичные ошибки при ручном формировании XML и использовании фабрики XDTO, а также представим готовые шаблоны кода для правильного решения этих задач.
Рассмотрим распространенную ошибку структуры циклов. При ручной сборке XML-документа с помощью объекта ЗаписьXML критически важно соблюдать строгую вложенность элементов. Часто разработчики пытаются сначала обойти все шапки документов в одном цикле, а затем — все табличные части в другом. Это приводит к тому, что в итоговом файле сначала выгружаются реквизиты всех накладных (номера, даты), а в самом конце файла сливаются в кучу строки их табличных частей. XML-структура при этом становится невалидной.
Для создания правильной иерархической структуры выгрузка должна происходить строго в рамках одного единого цикла по документам. Внутри этого цикла мы последовательно открываем тег документа, записываем его шапку, запускаем вложенный цикл по его же табличной части, закрываем тег табличной части и только потом закрываем тег самого документа. Давайте разберем правильный алгоритм на примере:
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("D:\126.xml", "UTF-8");
ЗаписьXML.ЗаписатьОбъявлениеXML();
// Открываем корневой элемент всего документа выгрузки
ЗаписьXML.ЗаписатьНачалоЭлемента("Документы");
Выборка = Документы.ПриходнаяНакладная.Выбрать();
Пока Выборка.Следующий() Цикл
// Начало блока конкретного документа - открываем строго ВНУТРИ цикла!
ЗаписьXML.ЗаписатьНачалоЭлемента("Документ");
// Записываем основные реквизиты шапки документа
ЗаписатьXML(ЗаписьXML, Выборка.Номер, "Номер");
ЗаписатьXML(ЗаписьXML, Выборка.Дата, "Дата");
ЗаписатьXML(ЗаписьXML, Выборка.СуммаПоДокументу, "СуммаДокумента");
// Открываем контейнер для табличной части конкретного документа
ЗаписьXML.ЗаписатьНачалоЭлемента("СписокНоменклатуры");
Для Каждого Стр Из Выборка.СписокНоменклатуры Цикл
// Открываем узел для отдельной строки табличной части
ЗаписьXML.ЗаписатьНачалоЭлемента("СтрокаНоменклатуры");
ЗаписатьXML(ЗаписьXML, Стр.Номенклатура.Код, "НоменклатураКод");
// Чтобы не передавать сложный объект ссылки, передаем наименование строкой
ЗаписатьXML(ЗаписьXML, Стр.Номенклатура.Наименование, "НоменклатураНаим");
ЗаписатьXML(ЗаписьXML, Стр.Количество, "Количество");
ЗаписатьXML(ЗаписьXML, Стр.Цена, "Цена");
ЗаписатьXML(ЗаписьXML, Стр.Сумма, "Сумма");
ЗаписьXML.ЗаписатьКонецЭлемента(); // Закрываем узел "СтрокаНоменклатуры"
КонецЦикла;
ЗаписьXML.ЗаписатьКонецЭлемента(); // Закрываем контейнер "СписокНоменклатуры"
ЗаписьXML.ЗаписатьКонецЭлемента(); // Закрываем узел "Документ"
КонецЦикла;
// Закрываем корневой элемент
ЗаписьXML.ЗаписатьКонецЭлемента(); // Документы
ЗаписьXML.Закрыть();
Этот простой подход гарантирует, что каждая строка табличной части будет привязана именно к своему документу, а итоговый файл XML будет иметь строго структурированный и понятный для внешних систем вид.
Вторая частая ошибка новичков — попытка назвать локальную переменную именем системной коллекции. Например, объявление переменной с именем Документы приводит к ошибке "Поле объекта недоступно для записи".
Это происходит потому, что идентификатор Документы зарезервирован платформой 1С на глобальном уровне для доступа к менеджерам всех документов конфигурации. Данный объект доступен только для чтения, и попытка переопределить его (например, написать Документы = ФабрикаXDTO.Создать(...)) вызывает сбой на этапе выполнения кода. Решается эта проблема очень просто: всегда используйте префиксы или альтернативные имена для ваших переменных. Вместо названия Документы назовите переменную мДокументы, МассивДокументов или ВыгружаемыеДокументы.
При использовании фабрики XDTO для генерации XML-файлов по схеме часто возникает ошибка: "Ошибка отображения типов: Отображение типа 'СправочникСсылка.Номенклатура' в тип...". Причина кроется в том, что в структуре вашей схемы XDTO для свойства (например, Номенклатура) указан простой тип данных (например, xs:string или anySimpleType), а код 1С пытается напрямую присвоить этому свойству объект типа СправочникСсылка.
Платформа не умеет автоматически преобразовывать сложные ссылочные типы метаданных 1С в примитивные типы XML-схем. Для решения этой проблемы у разработчика есть два основных пути в зависимости от требований к структуре файла.
Вариант А. Передача ссылки строковым представлением (простой путь)
Если принимающей стороне не нужно знать внутренний тип ссылки 1С, а требуется получить лишь текстовую информацию о товаре, передавайте строковое значение свойства. Мы можем извлечь уникальный идентификатор (GUID), код или наименование справочника. Посмотрим на примере кода:
// Вместо прямой передачи ссылки: СписокНоменклатуры.Номенклатура = стр.Номенклатура;
// Используйте передачу строкового представления:
// Вариант 1: Передаем наименование
СписокНоменклатуры.Номенклатура = Строка(стр.Номенклатура.Наименование);
// Вариант 2: Передаем уникальный идентификатор (GUID) для последующего поиска
СписокНоменклатуры.Номенклатура = Строка(стр.Номенклатура.УникальныйИдентификатор());
Вариант Б. Использование стандартных пространств имен типов 1С в XDTO (сложный путь)
Если XML-схема сторонней системы строго требует передачи объектов в формате типов данных 1С, необходимо правильно инициализировать XDTO-объект ссылки, используя фабрику и соответствующее пространство имен предприятия:
// Получаем тип ссылки из метаданных схемы XDTO
ТипСсылка = ФабрикаXDTO.Тип("http://v8.1c.ru/8.1/data/enterprise/current-config", "CatalogRef.Номенклатура");
// Создаем объект ссылки XDTO, инициализируя его через уникальный идентификатор
СсылкаXDTO = ФабрикаXDTO.Создать(ТипСсылка, Строка(стр.Номенклатура.УникальныйИдентификатор()));
// Теперь объект XDTO успешно примет типизированное значение
СписокНоменклатуры.Номенклатура = СсылкаXDTO;
Если перед вами не стоит задача сформировать XML-файл со строго заданной структурой от стороннего заказчика, а нужно просто перенести документы из одной базы 1С в другую (схожей конфигурации), ручное описание каждого узла — это лишняя трата времени. В платформу встроен мощнейший инструмент автоматической выгрузки — СериализаторXDTO.
С его помощью весь процесс выгрузки документа вместе со всеми его табличными частями, реквизитами шапки и служебными свойствами сводится буквально к нескольким строкам кода. Давайте проанализируем пример такой быстрой выгрузки:
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("C:\Обмен\ВыгрузкаДокументов.xml", "UTF-8");
ЗаписьXML.ЗаписатьОбъявлениеXML();
// Записываем корневой элемент-контейнер
ЗаписьXML.ЗаписатьНачалоЭлемента("ВсеДокументы");
// Прописываем системные пространства имен для корректного распознавания типов 1С
ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("V8Exch", "http://v8.1c.ru/8.1/edi/exch/type");
ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("xsi", "http://www.w3.org/2001/XMLSchema-instance");
ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("v8", "http://v8.1c.ru/8.1/data/enterprise");
Сериализатор = СериализаторXDTO;
Выборка = Документы.ПриходнаяНакладная.Выбрать();
Пока Выборка.Следующий() Цикл
// Получаем непосредственно объект документа (не ссылку!)
ОбъектДокумента = Выборка.ПолучитьОбъект();
// Сериализатор автоматически соберет XML-структуру всего документа
Сериализатор.ЗаписатьXML(ЗаписьXML, ОбъектДокумента);
КонецЦикла;
ЗаписьXML.ЗаписатьКонецЭлемента(); // ВсеДокументы
ЗаписьXML.Закрыть();
Преимущества использования Сериализатора XDTO:
Используйте ручную сборку через ЗаписьXML или кастомные пакеты XDTO, когда требуется сопряжение со сторонними API и внешними сервисами, имеющими жесткий регламент структуры файлов. Если же обмен происходит между конфигурациями на платформе 1С — всегда отдавайте предпочтение СериализаторXDTO, так как это значительно сократит время разработки и повысит отказоустойчивость вашей интеграции.