Чтение данных из XML-файла и их последующая обработка в таблице значений — одна из самых частых задач при интеграции 1С с внешними системами. Существует несколько способов решения этой задачи: от гибкого ручного парсинга до автоматизированного использования объектной модели XDTO. В этой статье мы подробно разберем каждый из методов, проанализируем типичные ошибки и выясним, как правильно считывать атрибуты узлов.
Этот способ считается наиболее современным и удобным. Фабрика XDTO позволяет представить XML-документ в виде дерева объектов, к свойствам которых можно обращаться «через точку». Это избавляет нас от необходимости вручную проверять типы узлов (начало элемента, текст, конец элемента). Для знакомства с базовыми принципами этой технологии подойдёт руководство по началу работы с XDTO.
Рассмотрим пример реализации. Важным нюансом здесь является обработка коллекций: если в XML-файле один элемент (например, одна строка товара), XDTO вернет объект. Если элементов несколько — вернется список. Чтобы код не выдавал ошибку, используем вспомогательную функцию.
&НаСервере
Процедура ЗагрузитьИзXML_XDTO(ИмяФайла)
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ИмяФайла);
// Используем стандартную фабрику
Попытка
ОтветXDTO = ФабрикаXDTO.ПрочитатьXML(Чтение);
Исключение
Сообщить("Ошибка чтения файла: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// Предположим, структура файла: Document -> Record
Для каждого Док ИЗ ПолучитьМассивXDTO(ОтветXDTO.Document) Цикл
Сообщить("Документ №: " + Док.Number);
Для каждого Запись из ПолучитьМассивXDTO(Док.Record) Цикл
// Здесь мы можем заполнять таблицу значений
НоваяСтрока = ТаблицаНоменклатуры.Добавить();
НоваяСтрока.Артикул = Запись.Barcode;
НоваяСтрока.Количество = Запись.Quantity;
КонецЦикла;
КонецЦикла;
Чтение.Закрыть();
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьМассивXDTO(XDTO_Объект)
// Функция гарантирует, что мы всегда работаем с коллекцией,
// даже если в XML всего один вложенный элемент
Если ТипЗнч(XDTO_Объект) = Тип("ОбъектXDTO") Тогда
Массив = Новый Массив;
Массив.Добавить(XDTO_Объект);
Возврат Массив;
Иначе
Возврат XDTO_Объект; // Это уже коллекция (СписокXDTO)
КонецЕсли;
КонецФункции
Если файл имеет очень большой объем (сотни мегабайт) или специфическую структуру, мы используем потоковый метод ЧтениеXML. Он потребляет минимум оперативной памяти, так как не загружает весь файл целиком, а читает его последовательно узел за узлом.
Разберем, как правильно организовать цикл обхода и избежать распространенной ошибки с потерей атрибутов. Важно помнить: атрибуты элемента доступны только тогда, когда ТипУзла равен ТипУзлаXML.НачалоЭлемента. Как только вы вызываете метод Прочитать(), чтобы перейти к тексту внутри тега, атрибуты самого тега становятся недоступны.
// Создаем таблицу значений для хранения данных
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("НомерДокумента", Новый ОписаниеТипов("Строка"));
ТЗ.Колонки.Добавить("Вес", Новый ОписаниеТипов("Число"));
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ИмяФайла);
Пока ЧтениеXML.Прочитать() Цикл
// Проверяем начало элемента (тега)
Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
// Если это нужный нам узел "Document", считываем его атрибуты сразу!
Если ЧтениеXML.Имя = "Document" Тогда
НовСтр = ТЗ.Добавить();
// Получаем значения атрибутов по именам
НовСтр.НомерДокумента = ЧтениеXML.ПолучитьАтрибут("Number");
НовСтр.Вес = Число(ЧтениеXML.ПолучитьАтрибут("TotalGrossWeight"));
// Если атрибутов много, можно перебрать их в цикле
Пока ЧтениеXML.ПрочитатьАтрибут() Цикл
ИмяАтрибута = ЧтениеXML.Имя;
ЗначениеАтрибута = ЧтениеXML.Значение;
// Обработка...
КонецЦикла;
КонецЕсли;
КонецЕсли;
КонецЦикла;
ЧтениеXML.Закрыть();
Проанализируем ситуацию, с которой часто сталкиваются начинающие разработчики. Если вы пытаетесь прочитать атрибут после того, как определили, что тип узла — Текст, система вернет Неопределено. Это происходит потому, что указатель в потоке чтения уже сдвинулся с заголовка тега (где находятся атрибуты) на его содержимое.
Правильная последовательность действий:
ТипУзлаXML.НачалоЭлемента.ПолучитьАтрибут() или ПрочитатьАтрибут().Если в вашей конфигурации используется Библиотека Стандартных Подсистем (БСП), можно воспользоваться готовым инструментом в модуле ОбщегоНазначения. Функция ПрочитатьXMLВТаблицу() предназначена для автоматического разбора XML определенной структуры (обычно той, которую 1С генерирует при выгрузке таблиц).
Рассмотрим, как это вызвать:
// В параметре передается объект ЧтениеXML
ТаблицаРезультат = ОбщегоНазначения.ПрочитатьXMLВТаблицу(ЧтениеXML);
Хотя этот метод требует жесткого соответствия структуры XML ожиданиям системы, он может служить отличным примером для написания собственного универсального парсера. Мы рекомендуем изучить код этой процедуры в конфигураторе, чтобы понять принципы сопоставления типов данных XML и колонок ТаблицыЗначений. При необходимости можно использовать обработку для преобразования данных XML в таблицу значений.
Для файлов среднего размера удобно использовать DOM (Document Object Model). Этот метод загружает всё дерево XML в память, что позволяет легко перемещаться «вверх» и «вниз» по иерархии, а также использовать запросы XPath.
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ИмяФайла);
// Создаем построитель и читаем весь документ в память
ПостроительDOM = Новый ПостроительDOM;
ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);
// Получаем все узлы с именем "Document"
УзлыДокументов = ДокументDOM.ПолучитьЭлементыПоИмени("Document");
Для каждого УзелДокумента Из УзлыДокументов Цикл
// Чтение атрибутов через карту атрибутов узла
АтрибутНомер = УзелДокумента.Атрибуты.ПолучитьИмя("Number");
Если АтрибутНомер <> Неопределено Тогда
Сообщить(АтрибутНомер.Значение);
КонецЕсли;
КонецЦикла;
ЧтениеXML.Закрыть();
Подводя итог, выбор метода зависит от ваших задач. Для интеграции со сторонними сервисами лучше всего подходит Фабрика XDTO. Если же нужно быстро «пробежаться» по огромному файлу и выдернуть пару значений — используйте ЧтениеXML, соблюдая правила работы с указателем узла.