Как проверить наличие документа в базе 1С:УТ 10.3 при загрузке из XML и пропустить дубликаты?

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

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

Наиболее наглядный способ работы с XML — это использование объектной модели DOM (Document Object Model). Суть этого метода заключается в том, что весь файл считывается в оперативную память и представляется в виде дерева узлов, по которым можно перемещаться в любом направлении. Проанализируем пример кода, который позволяет найти все узлы с именем «Документ» и проверить наличие атрибута «Номер».

Рассмотрим по шагам реализацию этого метода:


// Инициализируем чтение файла
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ПутьКФайлу);

// Создаем построитель DOM и считываем весь документ
ПостроительDOM = Новый ПостроительDOM;
ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);

// Получаем коллекцию всех узлов с тегом "Документ"
УзлыДокументов = ДокументDOM.ПолучитьЭлементыПоИмени("Документ");

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

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

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

Способ 2: Последовательное чтение и метод Пропустить()

Если мы хотим написать максимально производительный код, стоит использовать объект ЧтениеXML в режиме последовательного перебора. Проанализируем ситуацию: как нам «перепрыгнуть» через целый блок данных, если мы обнаружили, что документ уже существует? Для этого в платформе 1С предусмотрен метод Пропустить().

Разберем алгоритм действий:

  1. Читаем файл в цикле Пока ЧтениеXML.Прочитать().
  2. При нахождении начала элемента с именем «Документ» анализируем его атрибуты или вложенные значения.
  3. Если документ с таким номером уже есть в базе, вызываем ЧтениеXML.Пропустить(). Это мгновенно передвигает указатель чтения к закрывающему тегу текущего узла.

Посмотрим на пример реализации:


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

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

Этот метод гораздо бережнее относится к оперативной памяти и позволяет обрабатывать гигабайтные файлы обмена без потери производительности.

Критерии поиска: Номер или Уникальный Идентификатор?

Выясним причину, по которой поиск только по «Номеру» может быть ненадежным. В 1С:Управлении торговлей 10.3 нумерация документов часто является периодической (например, в пределах года). Это означает, что в базе может быть два документа с номером «000001»: один от 2023 года, другой от 2024. Поэтому при использовании метода НайтиПоНомеру крайне важно передавать вторым параметром дату, чтобы поиск велся в соответствующем периоде.

Однако самым правильным способом идентификации является использование UUID (уникального идентификатора). Если система, выгружающая XML, может передать ГУИД документа, мы можем однозначно найти его в базе:


ИдентификаторТекст = ЧтениеXML.ПолучитьАтрибут("GUID");
Если ЗначениеЗаполнено(ИдентификаторТекст) Тогда
    УникальныйИд = Новый УникальныйИдентификатор(ИдентификаторТекст);
    СсылкаНаДокумент = Документы.РеализацияТоваровУслуг.ПолучитьСсылку(УникальныйИд);
    
    // Проверяем, существует ли объект в базе на самом деле
    Если СсылкаНаДокумент.ПолучитьОбъект() <> Неопределено Тогда
        // Документ уже загружался ранее
        ЧтениеXML.Пропустить();
        Продолжить;
    КонецЕсли;
КонецЕсли;

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

Проанализируем ситуацию, когда документ в базе найден, но он помечен на удаление. В зависимости от логики вашей задачи, вы можете захотеть либо проигнорировать такой документ, либо «реанимировать» его, заполнив новыми данными из XML. Мы рекомендуем всегда добавлять проверку свойства ПометкаУдаления. Если найденная ссылка имеет установленную пометку, возможно, стоит сообщить об этом пользователю или программно снять пометку перед обновлением данных.

Также не забывайте про пространства имен (Namespaces). Если ваш XML содержит атрибут xmlns, то обычные методы ПолучитьЭлементыПоИмени могут не сработать без указания соответствующего URI пространства имен. Всегда проверяйте структуру входящего файла перед написанием кода парсинга.

Заключение

Мы рассмотрели два основных способа фильтрации дублей при загрузке XML. Для небольших файлов и простых задач идеально подходит ПостроительDOM, так как он позволяет обращаться к данным в произвольном порядке. Для высоконагруженных систем и больших объемов данных следует использовать ЧтениеXML с методом Пропустить(). Выбор правильного критерия поиска (Номер + Дата или GUID) гарантирует целостность вашей информационной базы и отсутствие «мусорных» записей.

← На главную