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

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

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

Проблема использования стандартной выборки

Рассмотрим стандартный подход, который часто приводит к ошибке. Если мы используем метод Выбрать(), система получает объект целиком со всеми его свойствами, включая те, которые были добавлены вручную. При попытке сериализации такого объекта в XML попадают все данные.

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


Запись = Новый ЗаписьXML;
Запись.УстановитьСтроку;
Запись.ЗаписатьОбъявлениеXML;
Запись.ЗаписатьНачалоЭлемента("Данные");

Выборка = Справочники.ФизическиеЛица.Выбрать;
Пока Выборка.Следующий() Цикл
    // Здесь записывается весь объект со всеми доп. реквизитами
    СериализаторXDTO.ЗаписатьXML(Запись, Выборка.ПолучитьОбъект); 
КонецЦикла;

Запись.ЗаписатьКонецЭлемента;
Текст = Запись.Закрыть;

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

Способ 1. Использование запроса для фильтрации полей

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   ФизЛица.Код КАК Код,
    |   ФизЛица.Наименование КАК Наименование,
    |   ФизЛица.ДатаРождения КАК ДатаРождения
    |ИЗ
    |   Справочник.ФизическиеЛица КАК ФизЛица";

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл
    // Создаем структуру для передачи только нужных данных
    ДанныеОбъекта = Новый Структура("Код, Наименование, ДатаРождения");
    ЗаполнитьЗначенияСвойств(ДанныеОбъекта, Выборка);
    
    // Сериализуем структуру, она более универсальна
    СериализаторXDTO.ЗаписатьXML(Запись, ДанныеОбъекта);
КонецЦикла;

Преимущество этого метода: мы полностью контролируем состав передаваемых данных и не зависим от изменений в структуре объекта источника.

Способ 2. Ручная запись XML-узлов

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


ЗаписьXML.ЗаписатьНачалоЭлемента("CatalogObject.ФизическиеЛица");

// Записываем только стандартные реквизиты
ЗаписьXML.ЗаписатьНачалоЭлемента("Наименование");
ЗаписьXML.ЗаписатьТекст(Объект.Наименование);
ЗаписьXML.ЗаписатьКонецЭлемента();

ЗаписьXML.ЗаписатьНачалоЭлемента("Код");
ЗаписьXML.ЗаписатьТекст(Объект.Код);
ЗаписьXML.ЗаписатьКонецЭлемента();

// Пропускаем самописные реквизиты
ЗаписьXML.ЗаписатьКонецЭлемента();

Этот способ требует написания большего объема кода, но позволяет детально настроить структуру файла.

Способ 3. Программная очистка XML-строки (метод "костыля")

Иногда требуется быстрое решение без изменения логики выборки данных. В этом случае можно получить XML-представление объекта в виде строки, удалить из нее лишние теги с помощью строковых функций или регулярных выражений, и только после этого записывать в итоговый файл.


// Получаем XML одного объекта
ЗаписьОдного = Новый ЗаписьXML;
ЗаписьОдного.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьОдного, Выборка.ПолучитьОбъект());
СтрXML = ЗаписьОдного.Закрыть();

// Пример удаления лишнего реквизита "ДополнительныйПараметр"
СтрXML = СтрЗаменить(СтрXML, "<ДополнительныйПараметр>", "");
// Здесь должна быть логика удаления содержимого и закрывающего тега

ЗаписьИтоговая.ЗаписатьТекст(СтрXML);

Важно: этот метод крайне не рекомендуется для постоянного использования, так как он медленный и подвержен ошибкам при изменении названий реквизитов.

Способ 4. Использование универсального обмена данными (КД 2.0 / 3.0)

Если обмен данными планируется на регулярной основе, рассмотрим вариант использования конфигурации "Конвертация данных". Это профессиональный инструмент, который специально предназначен для решения проблем несовпадения структур.

  1. Создадим правила обмена, где укажем соответствия только для типовых реквизитов.
  2. Используем обработку "Универсальный обмен данными в формате XML".
  3. В этом случае 1С сама сформирует корректный файл, игнорируя лишние данные, а загрузка пройдет без ошибок.

Способ 5. Обработка неизвестных узлов при чтении (метод Skip)

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

Разберем алгоритм:

  1. Читаем начало элемента через ЧтениеXML.Прочитать().
  2. Проверяем, существует ли реквизит с таким именем в метаданных текущей базы.
  3. Если реквизит существует — считываем значение.
  4. Если реквизита нет — вызываем ЧтениеXML.Пропустить(), чтобы перейти к следующему узлу, не вызывая ошибку.

Пока Чтение.Прочитать() Цикл
    Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
        ИмяУзла = Чтение.ЛокальноеИмя;
        Если Метаданные.Справочники.ФизическиеЛица.Реквизиты.Найти(ИмяУзла) <> Неопределено Тогда
            // Читаем данные
        Иначе
            // Игнорируем неизвестный реквизит
            Чтение.Пропустить();
        КонецЕсли;
    КонецЕсли;
КонецЦикла;

Рекомендации

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

← На главную