Как загрузить данные из XML в табличную часть обработки 1С

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

Работа с XML-файлами — это одна из самых частых задач при интеграции 1С с внешними системами или при загрузке файлов отчетности для ЭДО (например, Книги продаж или Книги покупок). В данной статье мы подробно разберем, как правильно прочитать структуру XML и перенести данные в табличную часть обработки, используя современные механизмы платформы.

Выбор метода чтения: ЧтениеXML vs ФабрикаXDTO

Существует два основных подхода к чтению XML в 1С. Рассмотрим их подробнее, чтобы понять, какой выбрать в вашем случае.

  1. Объект ЧтениеXML. Это последовательное чтение файла (SAX-подобный метод). Мы «бежим» по узлам и атрибутам. Этот метод хорош для очень больших файлов, так как он не загружает весь файл в память, но он требует написания большого объема кода для ручного разбора каждого тега.
  2. Механизм XDTO (ФабрикаXDTO). Это объектный подход. 1С считывает XML и превращает его в иерархическую структуру объектов. К данным можно обращаться «через точку», как к свойствам структуры. Это наиболее удобный способ для файлов среднего размера, в том числе когда требуется загрузка документов с шифрованием.

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


ХМЛ = Новый ЧтениеXML;
ХМЛ.ОткрытьФайл(ИмяФайла);
// Читаем весь файл в объектную модель XDTO
Данные = ФабрикаXDTO.ПрочитатьXML(ХМЛ);
ХМЛ.Закрыть();

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

Обработка коллекций (цикл по записям)

Одной из типичных проблем является ситуация, когда в XML может быть как одна запись, так и несколько. Если записей много, 1С воспринимает их как СписокXDTO. Если запись одна — как отдельный ОбъектXDTO. Чтобы код не «падал» с ошибкой, нужно правильно организовать цикл.

Рассмотрим, как реализовать универсальный обход записей СвПродаж:


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

Решение проблемы с разными атрибутами (ИННЮЛ и ИННФЛ)

Часто в XML-файлах налоговой отчетности данные контрагента могут находиться в разных атрибутах в зависимости от его типа: ИННЮЛ для юридических лиц или ИННФЛ для физических лиц. Попытка прямого обращения к отсутствующему свойству (например, ОбъектХМЛ.ИННЮЛ, если это физлицо) вызовет программную ошибку.

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


Для Каждого ОбъектХМЛ Из СписокЗаписей Цикл
    НоваяСтрока = Объект.Список.Добавить();
    
    // Заполняем простые реквизиты
    НоваяСтрока.НомерСФ = ОбъектХМЛ.НомерСчФ;
    
    // Обработка даты. В XML даты часто хранятся как строки типа "ГГГГ-ММ-ДД"
    // Используем XMLЗначение для корректного преобразования
    Попытка
        НоваяСтрока.ДатаСФ = XMLЗначение(Тип("Дата"), ОбъектХМЛ.ДатаСчФ);
    Исключение
        НоваяСтрока.ДатаСФ = Дата(1, 1, 1);
    КонецПопытки;

    // Логика выбора ИНН: проверяем наличие свойства ИННЮЛ
    Если ОбъектХМЛ.Свойства().Получить("ИННЮЛ") <> Неопределено Тогда
        ТекущийИНН = ОбъектХМЛ.ИННЮЛ;
    ИначеЕсли ОбъектХМЛ.Свойства().Получить("ИННФЛ") <> Неопределено Тогда
        ТекущийИНН = ОбъектХМЛ.ИННФЛ;
    Иначе
        ТекущийИНН = "";
    КонецЕсли;

    НоваяСтрока.ИНН = ТекущийИНН;
    
    // Поиск контрагента в базе по ИНН
    Если ЗначениеЗаполнено(ТекущийИНН) Тогда
        НоваяСтрока.Контрагент = Справочники.Контрагенты.НайтиПоРеквизиту("ИНН", ТекущийИНН);
    КонецЕсли;

    // Загрузка суммовых показателей
    НоваяСтрока.Сумма = ОбъектХМЛ.СтТовУчНалРубКоп;
    НоваяСтрока.СуммаНДС = ОбъектХМЛ.СумНДСРубКоп20;
КонецЦикла;

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

Выясним причину, почему загрузка больших файлов может занимать много времени. В примере выше мы используем НайтиПоРеквизиту внутри цикла. Если в файле 5 000 строк, система выполнит 5 000 отдельных запросов к базе данных. Это крайне неэффективно.

Проанализируем ситуацию и применим метод кэширования:

  1. Сбор ИНН. Перед циклом загрузки пройдите по XML и соберите все ИНН в массив.
  2. Один запрос. Сделайте один запрос к справочнику Контрагенты, чтобы найти все ссылки по этому списку ИНН.
  3. Соответствие. Результат запроса выгрузите в объект Соответствие, где Ключ — это ИНН, а Значение — Ссылка.
  4. Быстрое получение. В основном цикле просто получайте ссылку из Соответствия. Это ускорит загрузку в десятки раз.

Пример кода для оптимизации:


// Создаем соответствие для кэша
КэшКонтрагентов = Новый Соответствие;

// Запрос для получения всех контрагентов разом
Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|   Контрагенты.Ссылка КАК Ссылка,
|   Контрагенты.ИНН КАК ИНН
|ИЗ
|   Справочник.Контрагенты КАК Контрагенты
|ГДЕ
|   Контрагенты.ИНН В (&МассивИНН)";

Запрос.УстановитьПараметр("МассивИНН", МассивВсехИННизФайла);
Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл
    КэшКонтрагентов.Вставить(Выборка.ИНН, Выборка.Ссылка);
КонецЦикла;

// Теперь в цикле вместо НайтиПоРеквизиту используем:
НоваяСтрока.Контрагент = КэшКонтрагентов.Получить(ТекущийИНН);

Работа с большими файлами через ЧтениеXDTO

Если файл весит сотни мегабайт, метод ФабрикаXDTO.ПрочитатьXML вызовет ошибку нехватки памяти. В этом случае мы рекомендуем комбинированный метод: используем ЧтениеXML, чтобы «дойти» до нужного узла, и читаем только этот узел через XDTO.

Посмотрим на пример такого подхода:


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

// Переходим к началу элементов Документ или СвПродаж
Пока Чтение.Прочитать() Цикл
    Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента И Чтение.Имя = "СвПродаж" Тогда
        // Читаем только этот кусочек XML как объект XDTO
        ТипОбъекта = ФабрикаXDTO.Тип("http://www.v8.1c.ru/ssl/abc", "ТипСвПродаж"); // Укажите ваш тип
        ОбъектДанных = ФабрикаXDTO.ПрочитатьXDTO(Чтение);
        
        // Обрабатываем объект и идем дальше, память не перегружается
        ОбработатьДанные(ОбъектДанных);
    КонецЕсли;
КонецЦикла;

Таким образом, мы объединили простоту обращения через точку (XDTO) и экономичность последовательного чтения. Это решение является наиболее профессиональным при создании универсальных загрузчиков данных.

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

Используя данные подходы, вы сможете создать надежный и быстрый механизм загрузки любых XML-данных в ваши обработки 1С.

← На главную