При последовательной обработке XML-файлов с помощью объекта ЧтениеXML начинающие разработчики часто сталкиваются со ситуацией, когда попытка сопоставить имя элемента и его текстовое содержимое приводит к ошибке. Проблема возникает из-за того, как объектная модель 1С обрабатывает различные типы узлов и перебирает атрибуты. Разберем, почему возникает эта проблема и какими способами можно правильно прочитать данные из XML.
В процессе последовательного чтения файла объект ЧтениеXML проходит несколько разных типов узлов для каждого элемента:
ЧтениеXML.Имя (или ЧтениеXML.ЛокальноеИмя) содержит имя тега (например, Номер). Однако само текстовое значение элемента на данном этапе еще недоступно.Имя и Значение перезаписываются данными текущего атрибута (например, xsi:type="xs:string"). По окончании цикла контекст узла оказывается сдвинут.ЧтениеXML.ТипУзла принимает значение ТипУзлаXML.Текст. При этом свойство Имя становится пустым, а содержимое тега (например, 00000006435) попадает в свойство ЧтениеXML.Значение.Попытка проверить условие Если ЧтениеXML.Значение = "Номер" в блоке типа Текст ошибочна, так как Значение хранит строку 00000006435, а имя элемента было доступно только на этапе НачалоЭлемента.
Рассмотрим правильный подход к написанию цикла с использованием ЧтениеXML. Чтобы связать имя тега с его значением, необходимо запоминать имя элемента в отдельную переменную в момент обработки начального узла.
Посмотрим на пример кода:
ТекущееИмяТега = "";
Пока ЧтениеXML.Прочитать() Цикл
Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
// Запоминаем имя элемента до обработки его атрибутов или содержимого
ТекущееИмяТега = ЧтениеXML.ЛокальноеИмя;
ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.Текст Тогда
// Сравниваем сохраненное имя элемента с искомым
Если ТекущееИмяТега = "Номер" Тогда
СтрокаНомер = ЧтениеXML.Значение;
ИначеЕсли ТекущееИмяТега = "Дата" Тогда
СтрокаДата = ЧтениеXML.Значение;
КонецЕсли;
ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
// Сбрасываем имя при закрытии тега
ТекущееИмяТега = "";
КонецЕсли;
КонецЦикла;
Если требуется получить значение конкретного атрибута (например, тип данных), лучше использовать метод ПолучитьАтрибут("type") вместо полного цикла ПрочитатьАтрибут(), чтобы не сбивать указатель текущего узла.
Если файл был сформирован с использованием метода ЗаписатьXML с явным указанием типов (когда в XML присутствуют атрибуты xsi:type), платформе 1С не требуется ручной разбор типа данных. Для чтения таких узлов предназначен встроенный метод ПрочитатьXML().
Разберем по шагам, как это работает:
ЧтениеXML на нужный начальный элемент.ПрочитатьXML().Проанализируем пример кода:
Пока ЧтениеXML.Прочитать() Цикл
Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента И ЧтениеXML.ЛокальноеИмя = "Номер" Тогда
// Метод считывает значение тега и автоматически приводит его к типу 1С
ЗначениеНомера = ПрочитатьXML(ЧтениеXML);
КонецЕсли;
КонецЦикла;
Для удобной работы со всей структурой XML без написания сложных циклов последовательного чтения можно использовать механизмы XDTO. Метод ФабрикаXDTO.ПрочитатьXML() превращает XML-документ в объектную модель, где к дочерним узлам можно обращаться напрямую через точку.
Рассмотрим пример использования:
// Чтение XML-файла в объект XDTO
ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
// Доступ к значению тега "Номер" напрямую по имени
ЗначениеНомера = ОбъектXDTO.Номер;
Важное замечание: Чтение через ФабрикуXDTO или ПостроительDOM загружает весь файл в оперативную память. Для работы с файлами большого объема (сотни мегабайт) рекомендуется использовать потоковый разбор через ЧтениеXML с явным сохранением имени тега (Способ 1).