При обработке файлов формата XML или YML в 1С начинающие разработчики часто сталкиваются с ситуацией, когда метод ПолучитьАтрибут() возвращает значение Неопределено. Разберем, в чем заключается фундаментальное различие между атрибутами тегов и дочерними элементами, а также рассмотрим несколько способов правильного считывания данных.
Для понимания логики работы парсера проанализируем структуру типовой XML-записи:
<offer id="1001" available="true">
<vendorCode>ART-12345</vendorCode>
<picture>http://example.com/image.jpg</picture>
<param name="Мощность" unit="кВт">2.2</param>
</offer>
Разберем основные элементы этой структуры:
offer, vendorCode, picture и param.id="1001" и available="true" — это атрибуты тега offer, а name="Мощность" и unit="кВт" — атрибуты тега param.ART-12345 и http://example.com/image.jpg являются не атрибутами, а дочерними текстовыми узлами (ТипУзлаXML.Текст).Таким образом, попытка вызвать метод ПолучитьАтрибут("vendorCode") у элемента offer или picture возвращает Неопределено, потому что vendorCode не записан внутри заголовка тега как атрибут.
Объект ЧтениеXML осуществляет последовательный обход документа. Когда парсер находится на узле ТипУзлаXML.НачалоЭлемента с именем vendorCode, его текстовое содержимое находится на следующем шаге чтения. Для его получения необходимо выполнить дополнительный вызов метода Прочитать().
Рассмотрим правильный алгоритм потокового считывания кода номенклатуры и ссылки на изображение:
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ПутьКФайлу);
НоменКод = "";
КартинкаСсылка = "";
Пока ЧтениеXML.Прочитать() Цикл
Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
ИмяЭлемента = ЧтениеXML.Имя;
Если ИмяЭлемента = "vendorCode" Тогда
// Переходим к следующему узлу, который содержит текст
Если ЧтениеXML.Прочитать() И ЧтениеXML.ТипУзла = ТипУзлаXML.Текст Тогда
НоменКод = ЧтениеXML.Значение;
КонецЕсли;
ЭлЕсли ИмяЭлемента = "picture" Тогда
// Переходим к следующему узлу для получения ссылки
Если ЧтениеXML.Прочитать() И ЧтениеXML.ТипУзла = ТипУзлаXML.Текст Тогда
КартинкаСсылка = ЧтениеXML.Значение;
КонецЕсли;
КонецЕсли;
ЭлЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
Если ЧтениеXML.Имя = "offer" Тогда
// Завершили чтение элемента товара, выполняем поиск в базе
Если ЗначениеЗаполнено(НоменКод) Тогда
НоменВБазе = Справочники.Номенклатура.НайтиПоКоду(НоменКод);
// Обработка найденного объекта и сохранения картинки
КонецЕсли;
// Сбрасываем переменные для следующего товара
НоменКод = "";
КартинкаСсылка = "";
КонецЕсли;
КонецЕсли;
КонецЦикла;
ЧтениеXML.Закрыть();
Преимущество метода: минимальное потребление оперативной памяти. Этот подход идеально подходит для парсинга каталогов большого объема (сотни мегабайт).
Если размер XML-файла невеликов (до десятков мегабайт), удобнее загрузить документ в память целиком через объект ПостроительDOM. Это позволит обращаться к дочерним тегам напрямую по их имени без ручного контроля состояния потока.
Проанализируем пример чтения с помощью DOM:
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ПутьКФайлу);
ПостроительDOM = Новый ПостроительDOM;
ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);
СписокОфферов = ДокументDOM.ПолучитьЭлементыПоТегу("offer");
Для Каждого ЭлементOffer Из СписокОфферов Цикл
// Получение атрибутов тега offer
Идентификатор = ЭлементOffer.ПолучитьАтрибут("id");
// Получение значения дочернего тега vendorCode
СписокКодов = ЭлементOffer.ПолучитьЭлементыПоТегу("vendorCode");
НоменКод = "";
Если СписокКодов.Количество() > 0 Тогда
НоменКод = СписокКодов[0].ТекстовоеСодержимое;
КонецЕсли;
// Получение значения дочернего тега picture
СписокКартинок = ЭлементOffer.ПолучитьЭлементыПоТегу("picture");
КартинкаСсылка = "";
Если СписокКартинок.Количество() > 0 Тогда
КартинкаСсылка = СписокКартинок[0].ТекстовоеСодержимое;
КонецЕсли;
// Поиск номенклатуры по коду
Если ЗначениеЗаполнено(НоменКод) Тогда
НоменВБазе = Справочники.Номенклатура.НайтиПоКоду(НоменКод);
КонецЕсли;
КонецЦикла;
ЧтениеXML.Закрыть();
Еще один универсальный способ обработки XML в 1С — вызов метода ФабрикаXDTO.ПрочитатьXML(). При чтении документа без явного указания схемы XDTO создает динамический объект данных, в котором теги и атрибуты преобразуются в свойства объекта 1С.
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ПутьКФайлу);
// Считываем весь XML в объект XDTO
ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
// Обращаемся к свойствам структуры XDTO
Для Каждого ЭлементOffer Из ОбъектXDTO.shop.offers.offer Цикл
НоменКод = ЭлементOffer.vendorCode;
КартинкаСсылка = ЭлементOffer.picture;
// Получение атрибута
Идентификатор = ЭлементOffer.id;
КонецЦикла;
ЧтениеXML.Закрыть();
Выяснив различие между узлами и атрибутами XML, выбирайте подходящий инструмент под конкретную задачу:
ЧтениеXML с последовательным переходом на ТипУзлаXML.Текст.ПостроительDOM и свойство ТекстовоеСодержимое.ФабрикуXDTO.