Как получить значение из ОбъектXDTO, если тег определяется как объект, а не как простое значение?

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

При работе с XML-файлами через механизмы XDTO в 1С:Предприятии разработчики часто сталкиваются с ситуацией, когда ожидаемое простое значение (например, число или строка) внезапно превращается в ОбъектXDTO. Это особенно характерно для форматов типа YML или произвольных XML-выгрузок, где структура элементов может меняться или содержать пустые теги вида <weight/>.

В данной статье мы подробно разберем, почему так происходит, и проанализируем эффективные способы извлечения данных из таких объектов, основываясь на практическом опыте решения подобных задач.

Выясним причину: почему тег становится объектом?

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

Ситуация осложняется, если тег имеет так называемое «смешанное содержимое» (Mixed Content). В этом случае текст не привязан к конкретному свойству, а находится в специальной коллекции — последовательности. Именно поэтому прямое обращение к свойству или попытка преобразования типа Число(Категория.weight) вызывает ошибку, так как система видит перед собой структуру, а не значение.

Решение 1: Использование метода Последовательность()

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

Для этого мы можем использовать следующий алгоритм:


// Вес         
Попытка
    // Проверяем, существует ли само свойство в структуре объекта
    Если Категория.Свойства().Получить("weight") <> Неопределено Тогда
        
        // Анализируем последовательность объекта weight
        // Если количество элементов в последовательности не равно нулю, значит там есть текст или вложенные теги
        Если Категория.weight.Последовательность().Количество() <> 0 Тогда
        
            ВесЗначение = Категория.weight;
            
            // Выполняем заполнение реквизитов объекта Номенклатура
            Номенклатура.ВесИспользовать = Истина;
            Номенклатура.ВесЕдиницаИзмерения = НоменклатураСервер.ЕдиницаИзмеренияПоУмолчанию("Вес");    
            
            // Пробуем преобразовать полученное значение в число
            // Важно: если объект сложный, может потребоваться получение текста из последовательности
            Номенклатура.ВесЧислитель = Число(ВесЗначение); 
            Номенклатура.ВесМожноУказыватьВДокументах = Истина;
            Номенклатура.ВесЗнаменатель = 1;    
        
        КонецЕсли;
    КонецЕсли;
Исключение
    // Обработка исключения, если преобразование типов не удалось
    ЗаписьЖурналаРегистрации("XDTO.ОшибкаПарсинга", УровеньЖурналаРегистрации.Предупреждение, , , "Ошибка обработки веса");
КонецПопытки;

Решение 2: Явное извлечение текста из последовательности

Иногда простого обращения к объекту недостаточно, особенно если weight содержит атрибуты, но при этом является пустым. В таких случаях метод Последовательность().ПолучитьТекст(0) позволяет гарантированно вытащить строковое представление данных, находящихся между открывающим и закрывающим тегами.

Разберем пример более детального обхода:


Если Категория.ПроверитьУстановлено("weight") Тогда
    ОбъектВеса = Категория.weight;
    
    // Проверяем, является ли значение объектом
    Если ТипЗнч(ОбъектВеса) = Тип("ОбъектXDTO") Тогда
        ТекстовоеЗначение = "";
        
        // Собираем текст из всей последовательности
        Для Индекс = 0 По ОбъектВеса.Последовательность().Количество() - 1 Цикл
            ТекстовоеЗначение = ТекстовоеЗначение + ОбъектВеса.Последовательность().ПолучитьТекст(Индекс);
        КонецЦикла;
        
        Если ЗначениеЗаполнено(ТекстовоеЗначение) Тогда
            РезультатВес = Число(СтрЗаменить(ТекстовоеЗначение, ",", ".")); // Учитываем возможную разницу в разделителях
        КонецЕсли;
    Иначе
        // Если это не объект, а простое значение (строка/число)
        РезультатВес = Число(ОбъектВеса);
    КонецЕсли;
КонецЕсли;

Решение 3: Использование метода ПроверитьУстановлено()

Вместо использования метода Свойства().Получить(), который создает дополнительную коллекцию в памяти, рекомендуется использовать штатный метод ПроверитьУстановлено(). Это более производительный способ узнать, присутствует ли конкретный тег в текущем блоке XML.

Рассмотрим, как это упрощает код:

  1. Проверяем наличие свойства по имени.
  2. Если свойство установлено, анализируем его тип.
  3. Если тип является простым — считываем напрямую.
  4. Если тип сложный — работаем через последовательность или атрибуты.

Важный момент: если ваш XML содержит пустые теги типа <weight/>, то ПроверитьУстановлено() вернет Истина, но последовательность будет пустой. Это идеальный маркер для того, чтобы пропустить обработку незаполненных данных.

Особенности работы с атрибутами

Проанализируем ситуацию, когда значение передается не текстом, а атрибутом, например: <weight value="1.5"/>. В этом случае 1С также создаст ОбъектXDTO. Чтобы получить значение, нам нужно будет обратиться не к последовательности, а к свойству этого объекта:


Если Категория.weight.ПроверитьУстановлено("value") Тогда
    ЗначениеИзАтрибута = Категория.weight.value;
    // Дальнейшая логика обработки...
КонецЕсли;

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

Для корректной работы с XDTO при парсинге сложных XML-структур мы рекомендуем придерживаться следующих правил:

Применяя эти методы, вы сможете создать отказоустойчивый механизм импорта данных, который не «упадет» при встрече с пустыми или нестандартно структурированными элементами в XML-файле.

← На главную