Как получить текстовое значение XML-элемента при чтении файла в 1С?

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

При обработке файлов обмена в формате XML разработчики часто сталкиваются с ситуацией, когда атрибуты тега считываются без проблем, а значение внутри самого тега получить не удается — свойство Значение возвращает пустую строку.

Рассмотрим структуру XML-документа, разберем причину такого поведения потокового парсера ЧтениеXML и выясним, какими способами можно быстро и надежно прочитать как атрибуты, так и текстовое содержимое узлов в платформе 1С:Предприятие.

Почему Чт.Значение возвращает пустую строку?

Проанализируем исходный фрагмент XML:


<prices>
    <price type="RRP" currencyId="KZT">109990</price>
    <price type="Дилерская цена" currencyId="KZT">85117</price>
</prices>

Объект ЧтениеXML представляет собой последовательный потоковый считыватель (pull parser). Он двигается по документу шаг за шагом с помощью метода Прочитать(). Когда считыватель встречает открывающий тег <price ...>, свойство ТипУзла принимает значение ТипУзлаXML.НачалоЭлемента. На этом шаге доступны только имя тега (Чт.Имя) и его атрибуты.

Текстовые данные (в нашем примере число 85117) не являются частью открывающего тега — они представляют собой отдельный дочерний узел документа с типом ТипУзлаXML.Текст. Чтобы прочитать это число, необходимо продвинуть считыватель на следующий шаг.

Способ 1. Потоковое чтение с помощью ЧтениеXML

Потоковое чтение является самым производительным методом и потребляет минимальное количество оперативной памяти, что критически важно при обработке объемных файлов (каталогов товаров, прайс-листов на сотни мегабайт).

Разберем по шагам, как правильно организовать чтение атрибутов и значений тегов в одном цикле:

  1. Открываем файл или строковые данные с помощью объекта ЧтениеXML.
  2. В основном цикле обхода проверяем наступление события ТипУзлаXML.НачалоЭлемента для интересующего нас тега.
  3. Считываем атрибуты по их именам с помощью метода ПолучитьАтрибут(), так как обращение по числовому индексу ненадежно при изменении порядка атрибутов в файле.
  4. Если элемент не является пустым (проверяем флаг ПустойЭлемент), переходим к чтению содержимого до закрывающего тега ТипУзлаXML.КонецЭлемента.
  5. Фиксируем текст из узлов ТипУзлаXML.Текст и ТипУзлаXML.СекцияCDATA.

Посмотрим на практический пример реализации:


Чт = Новый ЧтениеXML;
Чт.ОткрытьФайл(ИмяФайла);

Пока Чт.Прочитать() Цикл
    // Проверяем начало нужного нам тега
    Если Чт.ТипУзла = ТипУзлаXML.НачалоЭлемента И Чт.Имя = "price" Тогда
        
        ТипЦены = Чт.ПолучитьАтрибут("type");
        Валюта  = Чт.ПолучитьАтрибут("currencyId");
        Цена    = "";
        
        // Если элемент самозакрывающийся (<price />), внутрь него заходить не нужно
        Если Не Чт.ПустойЭлемент Тогда
            
            // Читаем внутренние узлы до закрывающего тега </price>
            Пока Чт.Прочитать() Цикл
                
                Если Чт.ТипУзла = ТипУзлаXML.Текст Или Чт.ТипУзла = ТипУзлаXML.СекцияCDATA Тогда
                    Цена = Чт.Значение;
                ИначеЕсли Чт.ТипУзла = ТипУзлаXML.КонецЭлемента И Чт.Имя = "price" Тогда
                    // Выходим из внутреннего цикла при достижении закрывающего тега
                    Прервать;
                КонецЕсли;
                
            КонецЦикла;
            
        КонецЕсли;
        
        Сообщить(СтрШаблон("Тип: %1, Валюта: %2, Цена: %3", ТипЦены, Валюта, Цена));
        
    КонецЕсли;
КонецЦикла;

Чт.Закрыть();

Способ 2. Использование объектной модели DOM

Если размер XML-файла невелик (до нескольких десятков мегабайт) и он целиком помещается в оперативную память, гораздо удобнее использовать объектную модель документа (DOM). Объект ПостроительDOM считывает XML-файл и строит иерархическое дерево объектов, что избавляет от необходимости вручную контролировать указатель чтения.

Рассмотрим, как получить элементы по имени тега с помощью свойства ТекстовоеСодержимое:


Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ИмяФайла);

Построитель = Новый ПостроительDOM;
ДокументDOM = Построитель.Прочитать(Чтение);
Чтение.Закрыть();

// Получаем коллекцию всех узлов с именем price
СписокЦен = ДокументDOM.ПолучитьЭлементыПоИмени("price");

Для Каждого ЭлементЦены Из СписокЦен Цикл
    ТипЦены = ЭлементЦены.ПолучитьАтрибут("type");
    Валюта  = ЭлементЦены.ПолучитьАтрибут("currencyId");
    Цена    = ЭлементЦены.ТекстовоеСодержимое;
    
    Сообщить(СтрШаблон("Тип: %1, Валюта: %2, Цена: %3", ТипЦены, Валюта, Цена));
КонецЦикла;

Способ 3. Прямой поиск узлов через XPath

В случаях, когда из XML-документа требуется извлечь конкретное значение без перебора всех элементов (например, только значение для Дилерской цены), целесообразно использовать язык запросов XPath поверх загруженного ДокументDOM.

Посмотрим на пример выборки конкретного узла:


Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ИмяФайла);

Построитель = Новый ПостроительDOM;
ДокументDOM = Построитель.Прочитать(Чтение);
Чтение.Закрыть();

// Вычисляем XPath-выражение с фильтром по атрибуту
РезультатXPath = ДокументDOM.ВычислитьВыражениеXPath("/prices/price[@type='Дилерская цена']");
УзелЦены = РезультатXPath.ПолучитьСледующий();

Если УзелЦены <> Неопределено Тогда
    ДилерскаяЦена = УзелЦены.ТекстовоеСодержимое;
    Сообщить("Дилерская цена: " + ДилерскаяЦена);
КонецЕсли;

Рекомендации по выбору метода

Подведем итоги и определим, какой подход лучше выбрать под конкретную задачу:

  1. ЧтениеXML — идеальный выбор для больших файлов выгрузки (прайс-листы, каталоги номенклатуры, выгрузки банковских выписок). Позволяет обрабатывать файлы любого объема без риска переполнения памяти платформы 1С.
  2. ПостроительDOM и XPath — оптимальный вариант для компактных конфигурационных файлов, ответов веб-сервисов (REST/SOAP) и структурированных сообщений обмена, где важны простота кода и возможность быстрого поиска данных по условиям.
← На главную