Почему ЧтениеXML не возвращает значение элемента и как это исправить?

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

При работе с XML-файлами в среде 1С:Предприятие разработчики часто сталкиваются с ситуацией, когда при обходе дерева узлов объект ЧтениеXML возвращает пустое значение для тега, который визуально содержит текст. Например, в строке <price>150.0</price> ожидается получение числа "150.0", но свойство Значение оказывается пустой строкой. В этой статье мы подробно разберем, как устроена потоковая модель чтения XML, почему возникает эта сложность и какими способами можно надежно извлечь данные.

Разберем причину: почему значение узла пустое?

Для начала проанализируем ситуацию с точки зрения объектной модели 1С. Объект ЧтениеXML реализует так называемый "потоковый" (Forward-only) парсер. Он не загружает весь документ в память целиком, а двигается по нему последовательно, узел за узлом.

Важно понимать, что с точки зрения парсера простая конструкция <price>150.0</price> состоит не из одного, а из трех различных узлов:

  1. НачалоЭлемента (ТипУзлаXML.НачалоЭлемента): В этой точке курсор стоит на открывающем теге <price>. Здесь доступно Имя узла ("price"), но свойство Значение всегда будет пустым, так как сам тег не является текстом.
  2. Текст (ТипУзлаXML.Текст): Это отдельный узел, который находится "внутри" тегов. Именно здесь хранится строковое представление данных "150.0".
  3. КонецЭлемента (ТипУзлаXML.КонецЭлемента): Закрывающий тег </price>.

Рассмотрим типичный ошибочный код, с которым часто приходят на форумы:


Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
    Если Чтение.Имя = "price" Тогда
        // Ошибка: здесь Чтение.Значение всегда ""
        Сумма = Сумма + Число(Чтение.Значение); 
    КонецЕсли;
КонецЕсли;

В данном примере разработчик пытается получить значение в момент нахождения на "заголовке" тега. Программа видит, что это начало элемента "price", но текста там еще нет — он будет на следующем шаге чтения.

Решение №1: Ручной переход к текстовому узлу

Самый простой и очевидный способ исправить ситуацию — принудительно сдвинуть указатель чтения на следующий узел сразу после того, как мы обнаружили нужный нам тег НачалоЭлемента. Рассмотрим, как это выглядит в коде:


Пока Чтение.Прочитать() Цикл
    Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента И Чтение.Имя = "price" Тогда
        // Переходим от начала тега к его содержимому (узлу Текст)
        Чтение.Прочитать(); 
        Сумма = Сумма + Число(Чтение.Значение);
    КонецЕсли;
КонецЦикла;

Внимание: Этот метод рабочий, но он "хрупкий". Если XML-файл отформатирован с отступами и переносами строк, между НачалоЭлемента и Текст может оказаться узел типа ИгнорируемыеПробелы. В этом случае однократный вызов Прочитать() может не дойти до данных.

Решение №2: Использование специализированных методов (Рекомендуется)

Платформа 1С предоставляет более мощные и безопасные инструменты для извлечения содержимого. Рассмотрим методы ПрочитатьСодержимоеКакСтроку() и ПрочитатьСодержимоеКакЧисло(). Эти методы "умные": они сами считывают текстовый узел и перемещают курсор сразу к закрывающему тегу КонецЭлемента.

Проанализируем пример использования для нашей задачи:


Пока Чтение.Прочитать() Цикл
    Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента И Чтение.Имя = "price" Тогда
        // Метод сам найдет текст, пропустив пробелы, и вернет число
        // Он учитывает стандарт XML (точка как разделитель)
        Сумма = Сумма + Чтение.ПрочитатьСодержимоеКакЧисло();
    КонецЕсли;
КонецЦикла;

Преимущества этого подхода:

Решение №3: Настройка параметров чтения

Чтобы избежать проблем с "пустыми" узлами, возникающими из-за красивого форматирования XML (пробелы, табы), рекомендуется правильно инициализировать объект ЧтениеXML. Выясним, как это сделать с помощью параметров.


ПараметрыЧтения = Новый ПараметрыЧтенияXML(,,, ТипПроверкиXML.Нет, Истина);
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл("C:\data\prices.xml", ПараметрыЧтения);

Здесь последний параметр Истина указывает системе, что нужно игнорировать пустые пространства. В этом случае парсер будет "перепрыгивать" через переносы строк и отступы, оставляя в потоке только значимые узлы. Это делает разработку через Прочитать() гораздо стабильнее.

Работа с атрибутами

Иногда новички путают содержимое тега и его атрибуты. Разберем разницу на примере: <price currency="RUB">150.0</price>.

В этом случае "150.0" — это значение (текстовый узел), а "RUB" — это атрибут. Чтобы получить атрибут, не нужно двигаться по узлам. Нужно, находясь на узле НачалоЭлемента, вызвать соответствующий метод:


Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента И Чтение.Имя = "price" Тогда
    Валюта = Чтение.ПолучитьАтрибут("currency"); // Получим "RUB"
    Значение = Чтение.ПрочитатьСодержимоеКакЧисло(); // Получим 150.0
КонецЕсли;

Альтернатива: Использование XDTO

Если структура вашего XML-файла сложная и иерархичная, ручное перебирание узлов через ЧтениеXML может стать слишком трудоемким. В таких случаях стоит рассмотреть механизм XDTO (XML Data Transfer Objects).

Посмотрим на пример, как можно прочитать файл целиком в объектную модель:


Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл("C:\data\prices.xml");
// Читаем весь файл в объект
МойОбъект = ФабрикаXDTO.ПрочитатьXML(Чтение); 
// Обращаемся к данным как к свойствам объекта
Сумма = Сумма + МойОбъект.price;

Этот способ полностью избавляет от необходимости следить за типами узлов (начало, текст, конец), так как 1С сама преобразует XML в структуру объектов и коллекций.

Подведем итоги

Для эффективной работы с XML в 1С придерживайтесь следующих правил:

  1. Помните, что ЧтениеXML — это курсор. Он стоит либо на теге, либо на тексте.
  2. Используйте ПрочитатьСодержимоеКакСтроку() или аналоги для получения данных внутри тегов.
  3. Всегда устанавливайте параметр ИгнорироватьПробелы при открытии файла, чтобы избежать лишних итераций.
  4. Если файл большой и сложный, рассмотрите возможность использования XDTO для более высокоуровневой работы.
← На главную