При разборе XML-документов с помощью механизмов XDTO в платформе 1С разработчики нередко сталкиваются с ситуацией, когда тег содержит одновременно и атрибуты, и текстовое содержимое. Посмотрим на классический пример такого фрагмента:
<amount currencyName="RUR">40</amount>
<amountRub currencyName="RUR">40</amountRub>
Когда мы считываем такой фрагмент через стандартную фабрику без жесткой схемы, платформа создает ОбъектXDTO. При обращении к свойствам этого объекта мы без труда видим атрибут currencyName со значением "RUR", однако само значение суммы ("40") в списке привычных свойств объекта отсутствует. Выясним причину такого поведения платформы и разберем способы извлечения этих данных.
Проанализируем структуру модели данных XML Schema. Элемент, который одновременно несет в себе атрибуты и текстовый блок между тегами, описывается как сложный тип с простым содержимым (simpleContent) либо как смешанный тип (mixed).
Если чтение выполняется без строгой схемы либо если узел читается как неопределенный тип (anyType), платформа 1С автоматически создает ОбъектXDTO, у которого установлены свойства Последовательный = Истина и Смешанный = Истина. При этом XML-атрибуты становятся именованными свойствами объекта, а текстовый блок между открывающим и закрывающим тегами не получает собственного имени и помещается в специальную коллекцию — ПоследовательностьXDTO.
Рассмотрим прямое решение задачи. Если узел уже прочитан фабрикой в виде ОбъектXDTO, мы можем обратиться к его последовательности с помощью метода Последовательность().
Обратите внимание на важную деталь синтаксиса: метод Последовательность() вызывается у самого объекта узла (в нашем случае у объекта, представляющего тег amount), а не у его атрибута.
Разберем по шагам безопасный пример программного кода:
// Предположим, что УзелСуммы - это ОбъектXDTO для тега <amount currencyName="RUR">40</amount>
Если УзелСуммы.Тип().Последовательный Тогда
Последовательность = УзелСуммы.Последовательность();
Если Последовательность.Количество() > 0 Тогда
// Получаем текстовое содержимое первого блока
СтрокаСуммы = Последовательность.ПолучитьТекст(0);
Сумма = Число(СтрокаСуммы);
// Получаем значение атрибута
Валюта = УзелСуммы.currencyName;
КонецЕсли;
КонецЕсли;
Выделим ключевые нюансы работы с последовательностями XDTO, о которых важно помнить:
Последовательность() поддерживается только теми типами XDTO, у которых признак Последовательный равен Истина. Попытка вызвать метод у непоследовательного типа приведет к ошибке выполнения.ПолучитьТекст(0) извлекает текст по индексу 0. Если файл содержит пробелы, переносы строк или форматирование, первым элементом может оказаться пустая строка. Поэтому рекомендуется проверять количество элементов и при необходимости обходить коллекцию циклом.ПолучитьТекст() всегда возвращает данные с типом Строка. Приведение к числовому типу (через функцию Число()) разработчик выполняет явно.Если схема входящего XML-документа известна заранее, наилучшей практикой является создание собственного Пакета XDTO в дереве метаданных. Это позволяет обращаться к сумме напрямую через точку как к типизированному числу.
Разберем по шагам, как настроить тип в пакете XDTO:
currencyName, тип string и выбираем форму представления Атрибут.ЗначениеСуммы), указываем базовый тип decimal и устанавливаем форму представления Текст. Локальное имя XML для свойства с формой «Текст» не указывается.Текст, все остальные свойства этого объекта могут иметь только форму Атрибут. Дочерние теги (с формой Элемент) внутри такого типа использовать запрещено.После настройки схемы чтение документа выполняется с указанием типа, и обращение к данным становится максимально простым и строгим:
// Чтение с явным указанием типа из фабрики
ТипСуммы = ФабрикаXDTO.Тип("http://mycompany.ru/data", "AmountType");
ОбъектСумма = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML, ТипСуммы);
// Данные доступны сразу через точку с правильным типом Число:
Сумма = ОбъектСумма.ЗначениеСуммы;
Валюта = ОбъектСумма.currencyName;
Если использование XDTO не является обязательным требованием или структура файла часто меняется, разберем два других встроенных механизма платформы 1С:
ДокументDOM): позволяет получить текст элемента и его атрибуты без работы с последовательностями:
// УзелDOM соответствует элементу <amount>
СуммаСтрокой = УзелDOM.ТекстовоеСодержимое;
Валюта = УзелDOM.ПолучитьАтрибут("currencyName");
ЧтениеXML): оптимально для больших файлов, так как потребляет минимум оперативной памяти и работает быстрее объектных моделей:
// При позиционировании на открывающем теге amount:
Валюта = ЧтениеXML.ПолучитьАтрибут("currencyName");
ЧтениеXML.Прочитать(); // Переходим к содержимому
Если ЧтениеXML.ТипУзла = ТипУзлаXML.Текст Тогда
Сумма = Число(ЧтениеXML.Значение);
КонецЕсли;
Таким образом, для быстрого решения задачи при динамическом разборе через ОбъектXDTO достаточно использовать конструкцию Узел.Последовательность().ПолучитьТекст(0), а при регулярном обмене по фиксированным форматам наиболее надежным решением будет объявление типа со свойством в форме Текст в собственном пакете XDTO.