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

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

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

Разберем по шагам, как правильно прочитать файл XML, распарсить его содержимое, создать или обновить элементы справочника без дублей, а также выгрузить данные обратно.

1. Анализ распространенных ошибок при объявлении процедур и обходе XML

Рассмотрим типичные синтаксические ошибки, с которых часто начинается разработка механизмов импорта XML.

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


// ОШИБКА: Ожидается имя формального параметра
Процедура ПрочестьИз("D:\Work\User\Desktop\postav.xml") 
    // Код процедуры
КонецПроцедуры

В заголовке процедуры 1С должны указываться только имена переменных-параметров. Корректное объявление выглядит следующим образом:


Процедура ПрочестьИз(ПутьКФайлу)
    // Внутри процедуры работаем с переменной ПутьКФайлу
КонецПроцедуры

Вторая распространенная ошибка — обращение к некорректным или необъявленным переменным при обходе узлов XML через DOM (Document Object Model). Если цикл объявлен по переменной Элемент0, а внутри обращения идут к несуществующему объекту Contr, платформа выдаст ошибку «Переменная не определена»:


// ОШИБКА: Переменная Contr не определена
Для Каждого Элемент0 Из Документ.ЭлементДокумента.ДочерниеУзлы Цикл
    Если Элемент0.ИмяУзла = "Contr" Тогда
        КПП = Contr.Атрибуты.ПолучитьИменованныйЭлемент("KPP"); // Ошибка здесь!
    КонецЕсли;
КонецЦикла;

Для обращения к текущему узлу нужно использовать имя переменной цикла, то есть Элемент0.

2. Сравнение подходов к чтению XML в 1С: DOM, XDTO и последовательное чтение

Платформа 1С предлагает три основных инструмента для работы с XML-документами:

  1. Последовательное чтение (ЧтениеXML): Считывает файл строго по очереди узел за узлом. Отличается минимальным потреблением оперативной памяти, поэтому идеально подходит для файлов огромного объема (десятки и сотни мегабайт).
  2. Построитель DOM (ПостроительDOM): Полностью загружает структуру XML в оперативную память, создавая дерево объектов. Позволяет перемещаться по узлам в любых направлениях и выполнять поиск через XPath, но требователен к ресурсам.
  3. Фабрика XDTO (ФабрикаXDTO.ПрочитатьXML): Преобразует файл XML в высокоуровневые объекты XDTO. Это наиболее удобный и лаконичный способ для чтения структурированных файлов небольшого и среднего размера.

Проанализируем пример чтения файла поставщиков с помощью ФабрикаXDTO:


ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл("D:\Work\User\Desktop\postav.xml");

ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);

Для Каждого Contr Из ОбъектXDTO.RegContr.Contr Цикл
    Сообщить("ИНН: " + Contr.INN);
    Сообщить("КПП: " + Contr.KPP);
    Сообщить("Наименование: " + Contr.SNAME);
КонецЦикла;

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

3. Организация работы в управляемом приложении (Клиент-Сервер)

В управляемом приложении код разделен на клиентский и серверный контексты. Диалог выбора файла ДиалогВыбораФайла доступен только на клиенте (директива &НаКлиенте), однако сервер 1С не имеет прямого доступа к файловой системе компьютера пользователя.

Если сервер и клиент находятся на разных компьютерах, вызов ЧтениеXML.ОткрытьФайл(ПутьКФайлу) на сервере завершится ошибкой, так как по указанному пути на сервере файла не окажется.

Рассмотрим правильную организацию интерактивного выбора и передачи файла с клиента на сервер:


&НаКлиенте
Процедура ВыбратьИПрочитатьФайл(Команда)
    
    Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    Диалог.Фильтр = "Файлы XML (*.xml)|*.xml";
    Диалог.МножественныйВыбор = Ложь;
    
    Если Диалог.Выбрать() Тогда
        
        // Получаем выбранный путь на клиенте
        ПутьКФайлу = Диалог.ВыбранныеФайлы[0];
        
        // Читаем содержимое файла в строку на клиенте
        ТекстXML = Новый ТекстовыйДокумент;
        ТекстXML.Прочитать(ПутьКФайлу);
        СодержимоеXML = ТекстXML.ПолучитьТекст();
        
        // Передаем строку на сервер
        ОбработатьXMLНаСервере(СодержимоеXML);
        
    КонецЕсли;
    
КонецПроцедуры

&НаСервере
Процедура ОбработатьXMLНаСервере(СодержимоеXML)
    
    ЧтениеXML = Новый ЧтениеXML;
    ЧтениеXML.УстановитьСтроку(СодержимоеXML);
    
    ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
    
    // Дальнейшая обработка объектов XDTO на сервере...
    
    ЧтениеXML.Закрыть();
    
КонецПроцедуры

Метод ЧтениеXML.УстановитьСтроку() позволяет передавать текст XML-файла непосредственно в память без необходимости создавать временные файлы на стороне сервера.

4. Загрузка элементов в справочник с проверкой дублей и обновлением реквизитов

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

Важно помнить разницу между понятиями Ссылка и Объект:

Проанализируем алгоритм:

  1. Ищем поставщика по ключевому реквизиту (например, по ИНН).
  2. Если элемент не найден — создаем новый с помощью Справочники.Поставщики.СоздатьЭлемент().
  3. Если элемент найден — получаем его объект через .ПолучитьОбъект() для дозаполнения недостающих реквизитов.

&НаСервере
Процедура ЗагрузитьПоставщиковИзXDTO(ОбъектXDTO, ГруппаРодитель)
    
    Для Каждого Contr Из ОбъектXDTO.RegContr.Contr Цикл
        
        // Пропускаем записи без ИНН
        Если НЕ ЗначениеЗаполнено(Contr.INN) Тогда
            Продолжить;
        КонецЕсли;
        
        // Ищем существующего поставщика по ИНН
        СсылкаНайденного = Справочники.Поставщики.НайтиПоРеквизиту("ИНН", Contr.INN);
        
        Если СсылкаНайденного.Пустая() Тогда
            // Создаем новый элемент
            ОбъектПоставщик = Справочники.Поставщики.СоздатьЭлемент();
            ОбъектПоставщик.Наименование = Contr.SNAME;
            ОбъектПоставщик.ИНН = Contr.INN;
            ОбъектПоставщик.КПП = Contr.KPP;
            
            Если ЗначениеЗаполнено(ГруппаРодитель) Тогда
                ОбъектПоставщик.Родитель = ГруппаРодитель;
            КонецЕсли;
            
            ОбъектПоставщик.Записать();
        Иначе
            // Если элемент уже есть, обновляем пустые реквизиты
            ОбъектПоставщик = СсылкаНайденного.ПолучитьОбъект();
            Изменен = Ложь;
            
            Если НЕ ЗначениеЗаполнено(ОбъектПоставщик.КПП) И ЗначениеЗаполнено(Contr.KPP) Тогда
                ОбъектПоставщик.КПП = Contr.KPP;
                Изменен = Истина;
            КонецЕсли;
            
            Если Изменен Тогда
                ОбъектПоставщик.Записать();
            КонецЕсли;
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

5. Экспорт данных справочника в XML-файл

Рассмотрим обратную задачу — выгрузку данных из справочника Поставщики в файл XML. Попытка вызвать менеджер справочника Справочники.Поставщики.Выбрать() на клиенте вызовет ошибку «Переменная не определена (Справочники)», так как прямые обращения к БД на клиенте запрещены.

Сформируем выгрузку на сервере с использованием объекта ЗаписьXML:


&НаКлиенте
Процедура ЭкспортироватьПоставщиков(Команда)
    
    // Формируем текст XML на сервере
    ТекстXML = ПолучитьТекстВыгрузкиXMLНаСервере();
    
    // Сохраняем файл на клиенте
    Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Сохранение);
    Диалог.Фильтр = "Файлы XML (*.xml)|*.xml";
    Диалог.ПолноеИмяФайла = "postav_export.xml";
    
    Если Диалог.Выбрать() Тогда
        ТекстовыйДок = Новый ТекстовыйДокумент;
        ТекстовыйДок.УстановитьТекст(ТекстXML);
        ТекстовыйДок.Записать(Диалог.ПолноеИмяФайла);
        Сообщить("Выгрузка успешно завершена!");
    КонецЕсли;
    
КонецПроцедуры

&НаСервере
Функция ПолучитьТекстВыгрузкиXMLНаСервере()
    
    Запись = Новый ЗаписьXML;
    Запись.УстановитьСтроку();
    Запись.ЗаписатьОбъявлениеXML();
    
    Запись.ЗаписатьНачалоЭлемента("Root");
    Запись.ЗаписатьНачалоЭлемента("RegContr");
    
    Выборка = Справочники.Поставщики.Выбрать();
    Пока Выборка.Следующий() Цикл
        
        // Исключаем группы
        Если Выборка.ЭтоГруппа Тогда
            Продолжить;
        КонецЕсли;
        
        Запись.ЗаписатьНачалоЭлемента("Contr");
        Запись.ЗаписатьАтрибут("SNAME", Строка(Выборка.Наименование));
        Запись.ЗаписатьАтрибут("INN", Строка(Выборка.ИНН));
        Запись.ЗаписатьАтрибут("KPP", Строка(Выборка.КПП));
        Запись.ЗаписатьКонецЭлемента(); // Contr
        
    КонецЦикла;
    
    Запись.ЗаписатьКонецЭлемента(); // RegContr
    Запись.ЗаписатьКонецЭлемента(); // Root
    
    РезультатСтрокой = Запись.Закрыть();
    Возврат РезультатСтрокой;
    
КонецФункции

6. Лучшие практики и повышение производительности

Для создания надежных и быстрых алгоритмов обмена данными следует придерживаться следующих правил:

← На главную