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

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

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

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

Анализ структуры XML и причин ошибок при чтении

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

Посмотрим на пример обработки тегов при чтении файла. Если условие проверки имени узла настроено на один тег (например, ЭлементСправочника), а в реальности структура файла содержит разделение по категориям (tires, rims, camera), алгоритм записи просто не будет вызываться.

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


ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл("C:\Upload\data.xml");

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

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

Заполнение реквизитов справочника и работа со ссылочными типами

При записи данных в справочник Номенклатура важно различать примитивные типы (строки, числа, булево) и ссылочные реквизиты (подчиненные справочники брендов, размеров, категорий). Если реквизит Brand или Width имеет тип СправочникСсылка.Бренды, прямое присвоение строкового значения из XML вызовет ошибку или сбросит значение в пустую ссылку.

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

Рассмотрим пример процедуры создания элемента справочника Номенклатура с заполнением основных свойств:


Процедура ДобавитьЭлементШина(МассивДанных)

    НовыйЭлемент = Справочники.Номенклатура.СоздатьЭлемент();
    
    НовыйЭлемент.Артикул = МассивДанных.cae;
    НовыйЭлемент.Наименование = МассивДанных.name;
    
    // Поиск и заполнение ссылочного реквизита "Бренд"
    СсылкаБренд = Справочники.Производители.НайтиПоНаименованию(МассивДанных.brand);
    Если НЕ ЗначениеЗаполнено(СсылкаБренд) И ЗначениеЗаполнено(МассивДанных.brand) Тогда
        ОбъектБренд = Справочники.Производители.СоздатьЭлемент();
        ОбъектБренд.Наименование = МассивДанных.brand;
        ОбъектБренд.Записать();
        СсылкаБренд = ОбъектБренд.Ссылка;
    КонецЕсли;
    НовыйЭлемент.Бренд = СсылкаБренд;
    
    // Заполнение числовых и строковых характеристик
    НовыйЭлемент.Модель = МассивДанных.model;
    НовыйЭлемент.Ширина = МассивДанных.width;
    НовыйЭлемент.Диаметр = МассивДанных.diameter;
    
    НовыйЭлемент.Записать();

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

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

При регулярном импорте данных необходимо предотвратить создание повторяющихся позиций. Наиболее распространенным уникальным идентификатором товара во внешних файлах выступает артикул (код товара у поставщика).

Посмотрим, как организовать проверку наличия товара по артикулу перед созданием объекта с помощью метода НайтиПоРеквизиту:


Процедура ЗагрузитьДиски(МассивДисков)

    Для Каждого СтрокаДанных Из МассивДисков Цикл
        
        Артикул = СтрокаДанных.cae;
        
        Если НЕ ЗначениеЗаполнено(Артикул) Тогда
            Продолжить;
        КонецЕсли;
        
        // Поиск существующего элемента в базе
        СсылкаНоменклатура = Справочники.Номенклатура.НайтиПоРеквизиту("Артикул", Артикул);
        
        Если СсылкаНоменклатура = Справочники.Номенклатура.ПустаяСсылка() Тогда
            ОбъектНоменклатура = Справочники.Номенклатура.СоздатьЭлемент();
        Иначе
            ОбъектНоменклатура = СсылкаНоменклатура.ПолучитьОбъект();
        КонецЕсли;
        
        ОбъектНоменклатура.Артикул = Артикул;
        ОбъектНоменклатура.Наименование = СтрокаДанных.name;
        
        ОбъектНоменклатура.Записать();
        
    КонецЦикла;

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

Оптимизация производительности и рекомендации

Рассмотренный выше метод НайтиПоРеквизиту отлично подходит для небольших файлов. Однако если XML содержит десятки тысяч строк, обращение к базе данных в цикле существенно снизит скорость загрузки (проблема N+1 queries). Для высокой производительности и подготовки алгоритма к автоматическому заполнению через регламентные задания рекомендуется придерживаться следующих правил:

  1. Пакетный поиск через Запрос: Предварительно соберите все артикулы из XML в массив, выполните один запрос к таблице Справочник.Номенклатура с условием В (&МассивАртикулов) и выгрузите результат в Соответствие. Это позволит выполнять поиск существующих ссылок в оперативной памяти мгновенно.
  2. Индексация реквизитов: Убедитесь, что для реквизита Артикул в Конфигураторе выставлено свойство «Индексировать». Без этого поиск по реквизиту производит полное сканирование таблицы информационной базы.
  3. Использование транзакций: Оберните процесс записи массива объектов в блок НачатьТранзакцию() и ЗафиксироватьТранзакцию(). Запись порциями (по 500–1000 элементов) ускоряет процесс импорта в десятки раз.
  4. Кэширование вспомогательных справочников: Сохраняйте уже найденные ссылки на бренды, цвета и размеры в Соответствие, чтобы не производить повторные поисковые запросы к СУБД для одинаковых значений.
  5. Адаптация для фонового выполнения: Исключите из кода логики загрузки клиенто-ориентированные вызовы (такие как ОбновитьИнтерфейс() или Предупреждение()). Это позволит запускать обработку в фоновых и регламентных заданиях на сервере без участия пользователя.
← На главную