Чтение XML-файлов — одна из самых частых задач при интеграции 1С с внешними системами, маркетплейсами или при обмене данными. Однако при работе с реальными файлами (например, выгрузками товаров в формате YML) разработчики часто сталкиваются с проблемами: как правильно прочитать атрибуты узлов, как не переполнить память при обработке миллионов строк и какой метод выбрать — ЧтениеXML или XDTO. В этой статье мы подробно разберем все способы и научимся эффективно обрабатывать даже самые сложные структуры.
Если ваш файл содержит сотни тысяч или миллионы записей (например, офферы интернет-магазина), использование XDTO для всего файла целиком приведет к критической ошибке нехватки памяти. В таких случаях мы используем объект ЧтениеXML, который читает файл последовательно, не загружая его в оперативную память полностью. Рассмотрим, как правильно организовать цикл чтения и не запутаться в структуре.
Проанализируем пример кода, который позволяет перемещаться по узлам и определять их тип:
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ПутьКФайлу);
Пока Чтение.Прочитать() Цикл
// Проверяем тип узла: НачалоЭлемента, КонецЭлемента или Текст
Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
Если Чтение.Имя = "offer" Тогда
// Мы зашли внутрь карточки товара
Сообщить("Начало обработки товара...");
КонецЕсли;
// Пример чтения атрибутов узла
Пока Чтение.ПрочитатьАтрибут() Цикл
Если Чтение.Имя = "id" Тогда
Идентификатор = Чтение.Значение;
КонецЕсли;
КонецЦикла;
ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.Текст Тогда
// Здесь читается содержимое между тегами
Значение = Чтение.Значение;
КонецЕсли;
КонецЦикла;
Часто в XML встречаются узлы с одинаковым именем, но разными атрибутами. Классический пример — тег param, где имя характеристики (например, "Цвет", "Размер", "Штрихкод") передается в атрибуте name, а само значение — текстом внутри тега. Распространенная ошибка — вызвать Чтение.Прочитать() слишком рано и "проскочить" атрибут.
Разберем правильный алгоритм чтения таких узлов. Нам нужно сначала считать все атрибуты, сохранить нужное нам имя, а только затем переходить к чтению текстового содержимого:
Если Чтение.Имя = "param" Тогда
ИмяХарактеристики = "";
// 1. Сначала перебираем все атрибуты узла
Пока Чтение.ПрочитатьАтрибут() Цикл
Если Чтение.Имя = "name" Тогда
ИмяХарактеристики = Чтение.Значение;
КонецЕсли;
КонецЦикла;
// 2. Переходим к текстовому содержимому узла
Чтение.Прочитать();
ЗначениеХарактеристики = Чтение.Значение;
// 3. Обрабатываем результат
Если ИмяХарактеристики = "Штрихкод Вайлдберриз" Тогда
ШК = ЗначениеХарактеристики;
Сообщить("Найден штрихкод: " + ШК);
КонецЕсли;
КонецЕсли;
Как быть, если файл огромный (миллионы записей), но структура внутри одного узла (например, offer) очень сложная и писать десятки условий Если...ИначеЕсли неудобно? Идеальное решение — гибридный метод. Мы используем ЧтениеXML для поиска начала объекта, а затем "скармливаем" этот конкретный узел фабрике XDTO.
Это позволяет сочетать скорость потокового чтения и удобство обращения к свойствам через точку. Выясним, как это реализовать:
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ПутьКФайлу);
Пока Чтение.Прочитать() Цикл
// Ищем начало нужного нам объекта
Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента И Чтение.Имя = "offer" Тогда
// Читаем ВЕСЬ узел offer в объект XDTO (схема не обязательна)
Попытка
ОбъектТовар = ФабрикаXDTO.ПрочитатьXML(Чтение);
// Теперь мы можем обращаться к данным просто:
Артикул = ОбъектТовар.vendorCode;
Цена = ОбъектТовар.price;
// Если параметров много, они будут в коллекции
Для Каждого Параметр Из ОбъектТовар.param Цикл
Если Параметр.name = "Материал" Тогда
Сообщить(Параметр.Последовательность().ПолучитьТекст(0));
КонецЕсли;
КонецЦикла;
Исключение
Сообщить("Ошибка разбора оффера: " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецЦикла;
Когда речь идет о 7 миллионах записей, просто правильно прочитать XML недостаточно. Рассмотрим критически важные советы по оптимизации:
НачатьТранзакцию() и ЗафиксироватьТранзакцию().Чтение.ИгнорироватьПробелы = Истина;. Это избавит систему от необходимости создавать лишние узлы типа "Текст" для каждого отступа и перевода строки в XML-файле.XDTO не оставались в памяти. Внутри цикла старайтесь обнулять переменные, если они больше не нужны.& без надлежащего экранирования (&), ЧтениеXML выдаст ошибку. В таких случаях файл предварительно обрабатывают как текстовый документ, заменяя ошибочные символы.offer небольшой, но вам нужно выполнять в нем сложные поиски, можно использовать ПостроительDOM для конкретного узла. Это позволит использовать XPath-запросы для быстрого извлечения данных.Проанализируем ситуацию: вы вызвали Чтение.Прочитать(), чтобы получить текст тега, а потом вспомнили, что забыли прочитать атрибут этого же тега. К сожалению, вернуться назад невозможно. Атрибуты всегда считываются ПЕРЕД переходом к текстовому содержимому или вложенным узлам.
Также помните, что ФабрикаXDTO.ПрочитатьXML(Чтение) автоматически перемещает указатель чтения к концу прочитанного элемента. Вам не нужно дополнительно вызывать Прочитать() в конце цикла обработки XDTO, иначе вы пропустите следующий элемент.
Соблюдая эти правила и комбинируя низкоуровневое чтение с высокоуровневыми объектами XDTO, вы сможете построить надежную и быструю систему импорта данных любого объема.