Как получить текстовое значение XML-узла с атрибутами при чтении через Фабрику XDTO?

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

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


<amount currencyName="RUR">40</amount>
<amountRub currencyName="RUR">40</amountRub>

Когда мы считываем такой фрагмент через стандартную фабрику без жесткой схемы, платформа создает ОбъектXDTO. При обращении к свойствам этого объекта мы без труда видим атрибут currencyName со значением "RUR", однако само значение суммы ("40") в списке привычных свойств объекта отсутствует. Выясним причину такого поведения платформы и разберем способы извлечения этих данных.

Почему Фабрика XDTO не отображает значение в виде стандартного свойства?

Проанализируем структуру модели данных XML Schema. Элемент, который одновременно несет в себе атрибуты и текстовый блок между тегами, описывается как сложный тип с простым содержимым (simpleContent) либо как смешанный тип (mixed).

Если чтение выполняется без строгой схемы либо если узел читается как неопределенный тип (anyType), платформа 1С автоматически создает ОбъектXDTO, у которого установлены свойства Последовательный = Истина и Смешанный = Истина. При этом XML-атрибуты становятся именованными свойствами объекта, а текстовый блок между открывающим и закрывающим тегами не получает собственного имени и помещается в специальную коллекцию — ПоследовательностьXDTO.

Способ 1. Извлечение значения через коллекцию «ПоследовательностьXDTO»

Рассмотрим прямое решение задачи. Если узел уже прочитан фабрикой в виде ОбъектXDTO, мы можем обратиться к его последовательности с помощью метода Последовательность().

Обратите внимание на важную деталь синтаксиса: метод Последовательность() вызывается у самого объекта узла (в нашем случае у объекта, представляющего тег amount), а не у его атрибута.

Разберем по шагам безопасный пример программного кода:


// Предположим, что УзелСуммы - это ОбъектXDTO для тега <amount currencyName="RUR">40</amount>
Если УзелСуммы.Тип().Последовательный Тогда
    Последовательность = УзелСуммы.Последовательность();
    Если Последовательность.Количество() > 0 Тогда
        // Получаем текстовое содержимое первого блока
        СтрокаСуммы = Последовательность.ПолучитьТекст(0);
        Сумма = Число(СтрокаСуммы);
        
        // Получаем значение атрибута
        Валюта = УзелСуммы.currencyName;
    КонецЕсли;
КонецЕсли;

Выделим ключевые нюансы работы с последовательностями XDTO, о которых важно помнить:

  1. Проверка свойства «Последовательный»: метод Последовательность() поддерживается только теми типами XDTO, у которых признак Последовательный равен Истина. Попытка вызвать метод у непоследовательного типа приведет к ошибке выполнения.
  2. Безопасная индексация: метод ПолучитьТекст(0) извлекает текст по индексу 0. Если файл содержит пробелы, переносы строк или форматирование, первым элементом может оказаться пустая строка. Поэтому рекомендуется проверять количество элементов и при необходимости обходить коллекцию циклом.
  3. Преобразование типов: метод ПолучитьТекст() всегда возвращает данные с типом Строка. Приведение к числовому типу (через функцию Число()) разработчик выполняет явно.

Способ 2. Явное описание типа в пакете XDTO (форма представления «Текст»)

Если схема входящего XML-документа известна заранее, наилучшей практикой является создание собственного Пакета XDTO в дереве метаданных. Это позволяет обращаться к сумме напрямую через точку как к типизированному числу.

Разберем по шагам, как настроить тип в пакете XDTO:

  1. В пакете XDTO создаем новый Тип объекта.
  2. Добавляем свойство для атрибута валюты: задаем имя currencyName, тип string и выбираем форму представления Атрибут.
  3. Добавляем свойство для суммы: задаем имя (например, ЗначениеСуммы), указываем базовый тип decimal и устанавливаем форму представления Текст. Локальное имя XML для свойства с формой «Текст» не указывается.
  4. Важное платформенное ограничение: если у типа объекта задано свойство с формой представления Текст, все остальные свойства этого объекта могут иметь только форму Атрибут. Дочерние теги (с формой Элемент) внутри такого типа использовать запрещено.

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


// Чтение с явным указанием типа из фабрики
ТипСуммы = ФабрикаXDTO.Тип("http://mycompany.ru/data", "AmountType");
ОбъектСумма = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML, ТипСуммы);

// Данные доступны сразу через точку с правильным типом Число:
Сумма = ОбъектСумма.ЗначениеСуммы; 
Валюта = ОбъектСумма.currencyName;

Способ 3. Альтернативные методы разбора (DOM и потоковое чтение)

Если использование XDTO не является обязательным требованием или структура файла часто меняется, разберем два других встроенных механизма платформы 1С:

  1. Объектная модель DOM (ДокументDOM): позволяет получить текст элемента и его атрибуты без работы с последовательностями:
    
    // УзелDOM соответствует элементу <amount>
    СуммаСтрокой = УзелDOM.ТекстовоеСодержимое;
    Валюта = УзелDOM.ПолучитьАтрибут("currencyName");
    
  2. Потоковое чтение (ЧтениеXML): оптимально для больших файлов, так как потребляет минимум оперативной памяти и работает быстрее объектных моделей:
    
    // При позиционировании на открывающем теге amount:
    Валюта = ЧтениеXML.ПолучитьАтрибут("currencyName");
    ЧтениеXML.Прочитать(); // Переходим к содержимому
    Если ЧтениеXML.ТипУзла = ТипУзлаXML.Текст Тогда
        Сумма = Число(ЧтениеXML.Значение);
    КонецЕсли;
    

Таким образом, для быстрого решения задачи при динамическом разборе через ОбъектXDTO достаточно использовать конструкцию Узел.Последовательность().ПолучитьТекст(0), а при регулярном обмене по фиксированным форматам наиболее надежным решением будет объявление типа со свойством в форме Текст в собственном пакете XDTO.

← На главную