Как прочитать XML в 1С: работа с атрибутами, XDTO и оптимизация больших файлов

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

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

Последовательное чтение с помощью объекта ЧтениеXML

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

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


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

Пока Чтение.Прочитать() Цикл
    // Проверяем тип узла: НачалоЭлемента, КонецЭлемента или Текст
    Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
        
        Если Чтение.Имя = "offer" Тогда
            // Мы зашли внутрь карточки товара
            Сообщить("Начало обработки товара...");
        КонецЕсли;

        // Пример чтения атрибутов узла
        Пока Чтение.ПрочитатьАтрибут() Цикл
            Если Чтение.Имя = "id" Тогда
                Идентификатор = Чтение.Значение;
            КонецЕсли;
        КонецЦикла;

    ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.Текст Тогда
        // Здесь читается содержимое между тегами
        Значение = Чтение.Значение;
    КонецЕсли;
КонецЦикла;

Проблема повторяющихся узлов с атрибутами (теги param)

Часто в XML встречаются узлы с одинаковым именем, но разными атрибутами. Классический пример — тег param, где имя характеристики (например, "Цвет", "Размер", "Штрихкод") передается в атрибуте name, а само значение — текстом внутри тега. Распространенная ошибка — вызвать Чтение.Прочитать() слишком рано и "проскочить" атрибут.

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


Если Чтение.Имя = "param" Тогда
    ИмяХарактеристики = "";
    
    // 1. Сначала перебираем все атрибуты узла
    Пока Чтение.ПрочитатьАтрибут() Цикл
        Если Чтение.Имя = "name" Тогда
            ИмяХарактеристики = Чтение.Значение;
        КонецЕсли;
    КонецЦикла;

    // 2. Переходим к текстовому содержимому узла
    Чтение.Прочитать(); 
    ЗначениеХарактеристики = Чтение.Значение;

    // 3. Обрабатываем результат
    Если ИмяХарактеристики = "Штрихкод Вайлдберриз" Тогда
        ШК = ЗначениеХарактеристики;
        Сообщить("Найден штрихкод: " + ШК);
    КонецЕсли;
КонецЕсли;

Гибридный метод: Поточное чтение + XDTO

Как быть, если файл огромный (миллионы записей), но структура внутри одного узла (например, offer) очень сложная и писать десятки условий Если...ИначеЕсли неудобно? Идеальное решение — гибридный метод. Мы используем ЧтениеXML для поиска начала объекта, а затем "скармливаем" этот конкретный узел фабрике XDTO.

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


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

Пока Чтение.Прочитать() Цикл
    // Ищем начало нужного нам объекта
    Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента И Чтение.Имя = "offer" Тогда
        
        // Читаем ВЕСЬ узел offer в объект XDTO (схема не обязательна)
        Попытка
            ОбъектТовар = ФабрикаXDTO.ПрочитатьXML(Чтение);
            
            // Теперь мы можем обращаться к данным просто:
            Артикул = ОбъектТовар.vendorCode;
            Цена = ОбъектТовар.price;
            
            // Если параметров много, они будут в коллекции
            Для Каждого Параметр Из ОбъектТовар.param Цикл
                Если Параметр.name = "Материал" Тогда
                    Сообщить(Параметр.Последовательность().ПолучитьТекст(0));
                КонецЕсли;
            КонецЦикла;
        Исключение
            Сообщить("Ошибка разбора оффера: " + ОписаниеОшибки());
        КонецПопытки;
        
    КонецЕсли;
КонецЦикла;

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

Когда речь идет о 7 миллионах записей, просто правильно прочитать XML недостаточно. Рассмотрим критически важные советы по оптимизации:

  1. Использование транзакций. Никогда не записывайте данные в базу внутри цикла чтения по одной штуке. Это убьет производительность. Нарезайте данные "порциями" по 500-1000 элементов и фиксируйте транзакцию через НачатьТранзакцию() и ЗафиксироватьТранзакцию().
  2. Игнорирование пробелов. Установите свойство Чтение.ИгнорироватьПробелы = Истина;. Это избавит систему от необходимости создавать лишние узлы типа "Текст" для каждого отступа и перевода строки в XML-файле.
  3. Очистка памяти. Если вы используете гибридный метод, следите за тем, чтобы ссылки на объекты XDTO не оставались в памяти. Внутри цикла старайтесь обнулять переменные, если они больше не нужны.
  4. Спецсимволы. Если файл содержит символы типа & без надлежащего экранирования (&), ЧтениеXML выдаст ошибку. В таких случаях файл предварительно обрабатывают как текстовый документ, заменяя ошибочные символы.
  5. ПостроительDOM. Если узел offer небольшой, но вам нужно выполнять в нем сложные поиски, можно использовать ПостроительDOM для конкретного узла. Это позволит использовать XPath-запросы для быстрого извлечения данных.

Типичные ошибки, которых следует избегать

Проанализируем ситуацию: вы вызвали Чтение.Прочитать(), чтобы получить текст тега, а потом вспомнили, что забыли прочитать атрибут этого же тега. К сожалению, вернуться назад невозможно. Атрибуты всегда считываются ПЕРЕД переходом к текстовому содержимому или вложенным узлам.

Также помните, что ФабрикаXDTO.ПрочитатьXML(Чтение) автоматически перемещает указатель чтения к концу прочитанного элемента. Вам не нужно дополнительно вызывать Прочитать() в конце цикла обработки XDTO, иначе вы пропустите следующий элемент.

Соблюдая эти правила и комбинируя низкоуровневое чтение с высокоуровневыми объектами XDTO, вы сможете построить надежную и быструю систему импорта данных любого объема.

← На главную