Как исправить ошибку преобразования XML при загрузке групп справочника через планы обмена в 1С?

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

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

Причины возникновения ошибки десериализации

Проанализируем механизм работы стандартного обмена данными. При выгрузке и загрузке объектов через планы обмена платформа 1С использует объект СериализаторXDTO. Он выполняет строгое сопоставление узлов XML-документа с типами и свойствами объектов метаданных конфигурации-приемника.

Ошибка чтения группы возникает по двум основным причинам:

  1. Настройка видимости реквизита в метаданных: У реквизитов иерархических справочников есть свойство метаданных Использование реквизита. Если в базе-источнике или базе-приемнике у реквизита установлено значение Для элемента, объект группы в оперативной памяти платформы не имеет этого реквизита. При наличии соответствующего тега в XML-файле десериализатор не может сопоставить узел со свойством объекта группы и аварийно прерывает чтение.
  2. Различие в составе метаданных: Если в базе-источнике добавлены новые реквизиты, а в базе-приемнике их нет, прямой вызов СериализаторXDTO.ПрочитатьXML() не сможет пропустить неизвестные теги, так как схема типа не совпадает со структурой пакета.

Способ 1. Корректировка свойства метаданных реквизитов

Самый простой и быстрый способ решения проблемы без переписывания программного кода обмена — согласование свойств метаданных в обеих информационных базах.

Выполним следующие шаги:

  1. Откроем дерево метаданных конфигурации в конфигураторе.
  2. Найдем проблемный справочник и развернем список его реквизитов.
  3. Для каждого реквизита, вызывающего ошибку при загрузке папок, откроем окно свойств (палитру свойств).
  4. Найдем свойство Использование реквизита и установим для него значение Для группы и элемента.
  5. Сохраним и применим изменения конфигурации базы данных.

После изменения этого свойства объект группы получит соответствующее свойство в модели данных. Даже если для групп эти реквизиты останутся незаполненными, СериализаторXDTO сможет корректно прочитать входящий XML без ошибок несоответствия схемы.

Способ 2. Фильтрация данных при выгрузке в модуле плана обмена

Если изменять структуру метаданных в конфигурации-приемнике нежелательно, перехватим процесс записи данных на стороне базы-источника. Для этого используем события плана обмена в модуле плана обмена.

Рассмотрим пример переопределения выгрузки в обработчике ПриОтправкеДанныхГлавному или ПриОтправкеДанныхПодчиненному:


Процедура ПриОтправкеДанныхПодчиненному(ЭлементДанных, ОтправкаЭлемента, СозданиеСообщения)
    
    // Проверяем тип отправляемого объекта
    Если ТипЗнч(ЭлементДанных) = Тип("СправочникОбъект.Товары") Тогда
        // Если выгружается группа, очищаем значения специфических реквизитов
        Если ЭлементДанных.ЭтоГруппа Тогда
            // При необходимости можно переопределить запись объекта через фабрику XDTO
            // или исключить лишние данные перед помещением в поток
        КонецЕсли;
    КонецЕсли;

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

Способ 3. Поузловое чтение с ручным созданием объектов

Когда структуры конфигураций сильно различаются и прямое использование платформенного сериализатора невозможно, разберем вариант с выборочной загрузкой с помощью объектов ЧтениеXML и СправочникиМенеджер.

Посмотрим на пример процедуры выборочной загрузки элементов и групп:


Процедура ЗагрузитьТоварыИзXML(ПутьКФайлу)

    ЧтениеXML = Новый ЧтениеXML;
    ЧтениеXML.ОткрытьФайл(ПутьКФайлу);

    Пока ЧтениеXML.Прочитать() Цикл
        Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента И ЧтениеXML.Имя = "CatalogObject.Товары" Тогда
            
            // Читаем параметры текущего объекта
            ЭтоГруппа = Ложь;
            УникальныйИдентификатор = Неопределено;
            Наименование = "";
            
            // Считываем дочерние узлы объекта
            Пока ЧтениеXML.Прочитать() Цикл
                Если ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента И ЧтениеXML.Имя = "CatalogObject.Товары" Тогда
                    Прервать;
                КонецЕсли;
                
                Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
                    ИмяУзла = ЧтениеXML.Имя;
                    ЧтениеXML.Прочитать(); // Переходим к значению
                    
                    Если ИмяУзла = "IsFolder" Тогда
                        ЭтоГруппа = (ЧтениеXML.Значение = "true");
                    ИначеЕсли ИмяУзла = "Ref" Тогда
                        УникальныйИдентификатор = Новый УникальныйИдентификатор(ЧтениеXML.Значение);
                    ИначеЕсли ИмяУзла = "Description" Тогда
                        Наименование = ЧтениеXML.Значение;
                    КонецЕсли;
                КонецЕсли;
            КонецЦикла;
            
            // Создаем или находим объект в базе
            Если ЗначениеЗаполнено(УникальныйИдентификатор) Тогда
                СсылкаНаОбъект = Справочники.Товары.ПолучитьСсылку(УникальныйИдентификатор);
                
                Если ЭтоГруппа Тогда
                    ОбъектТовар = Справочники.Товары.СоздатьГруппу();
                Иначе
                    ОбъектТовар = Справочники.Товары.СоздатьЭлемент();
                КонецЕсли;
                
                ОбъектТовар.УстановитьСсылкуНового(СсылкаНаОбъект);
                ОбъектТовар.Наименование = Наименование;
                
                // Записываем объект без попытки заполнить отсутствующие реквизиты
                Попытка
                    ОбъектТовар.Записать();
                Исключение
                    ЗаписьЖурналаРегистрации("ОбменДанными", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
                КонецПопытки;
            КонецЕсли;
            
        КонецЕсли;
    КонецЦикла;

    ЧтениеXML.Закрыть();

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

Способ 4. Использование инструментов «1С:Конвертация данных»

Если обмен между разнородными базами требует постоянной поддержки и развивается, лучшим решением будет переход со стандартного прямого чтения через планы обмена на специализированные правила конвертации (КД 2.1 или КД 3.0):

  1. В Конвертации данных 2.1 в правилах конвертации свойств (ПКС) для реквизитов, не предназначенных для групп, достаточно добавить условие в обработчик ПередВыгрузкой:
    
    Если Объект.ЭтоГруппа Тогда
        Отказ = Истина;
    КонецЕсли;
    
  2. В Конвертации данных 3.0 (EnterpriseData) разделение сущностей элементов и папок реализовано на уровне схемы XDTO-пакета формата обмена, что исключает появление реквизитов элементов внутри описания групп.

Выбор конкретного метода зависит от возможности внесения изменений в конфигурации: для типовых конфигураций на поддержке оптимально использовать правила конвертации данных, а при наличии доступа к доработке конфигураций — скорректировать свойство Использование реквизита в метаданных.

← На главную