При загрузке и обработке данных из XML-файлов в системе 1С мы часто сталкиваемся с необходимостью работать с объектами XDTO. Эти объекты представляют собой структурированные данные, соответствующие определенной схеме. Однако, если структура входящего XML-файла не всегда соответствует ожидаемой или содержит необязательные поля, попытка прямого обращения к отсутствующему полю может привести к распространенной ошибке "Поле объекта не обнаружено". Рассмотрим подробнее, как мы можем избежать этой проблемы и безопасно проверять наличие и значение полей в объектах XDTO. Для базового знакомства с технологией можно использовать руководство по основам работы с XDTO с нуля.
Исходная проблема, с которой мы столкнулись, выглядит следующим образом:
ЭтоКолекция = ?(ТипЗнч(тОбъектОбмена.ТабличнаяЧасть[1].Запись) = Тип("ОбъектXDTO")
В этой строке кода происходит попытка прямого обращения к полю Запись объекта, находящегося в табличной части XDTO. Если в элементе тОбъектОбмена.ТабличнаяЧасть[1] поле Запись отсутствует, система выдаст ошибку. Наша задача — научиться заранее проверять наличие этого поля.
Прежде чем углубляться в проверку свойств, давайте сначала убедимся, что мы работаем с объектом XDTO. В нашем случае, вопрос возник после получения информации, что ТипЗнч(тОбъектОбмена.ТабличнаяЧасть[1]) является ОбъектXDTO. Это критически важно, так как методы, которые мы будем использовать, применимы именно к этому типу объектов.
ТипЗнч(тОбъектОбмена.ТабличнаяЧасть[1]) // Должно быть ОбъектXDTO
Если бы это был другой тип, например, примитивный тип или СписокXDTO, подходы к доступу к данным могли бы отличаться.
Свойства.Получить(ИмяСвойства) для проверки существования поляОдин из наиболее надежных и часто используемых способов проверки наличия свойства в объекте XDTO — это применение метода Свойства.Получить(). Этот метод позволяет нам запросить информацию о свойстве по его имени, не вызывая ошибки, если свойство отсутствует.
Как это работает:
Свойства объекта XDTO.Получить(), передавая ему имя интересующего нас свойства в виде строки.СвойствоXDTO, если свойство с таким именем найдено в схеме объекта XDTO.Неопределено.Таким образом, мы можем безопасно проверить наличие свойства, прежде чем пытаться получить его значение.
Свойства.Получить():
ИмяСвойства = "Запись";
ОбъектТЧ = тОбъектОбмена.ТабличнаяЧасть[1]; // Допустим, это ОбъектXDTO
// Шаг 1: Получаем информацию о свойстве
СвойствоЗапись = ОбъектТЧ.Свойства.Получить(ИмяСвойства);
// Шаг 2: Проверяем, существует ли свойство
Если СвойствоЗапись <> Неопределено Тогда
// Свойство "Запись" существует, теперь мы можем безопасно получить его значение
ЗначениеЗаписи = ОбъектТЧ.Получить(ИмяСвойства);
// Дополнительная проверка на тип, если необходимо
Если ТипЗнч(ЗначениеЗаписи) = Тип("ОбъектXDTO") Тогда
// Продолжаем работать со ЗначениеЗаписи как с ОбъектXDTO
Сообщить("Свойство " + ИмяСвойства + " существует и является ОбъектXDTO.");
Иначе
Сообщить("Свойство " + ИмяСвойства + " существует, но имеет другой тип: " + ТипЗнч(ЗначениеЗаписи));
КонецЕсли;
Иначе
// Свойство "Запись" отсутствует в данном элементе XDTO
Сообщить("Свойство " + ИмяСвойства + " не найдено в элементе табличной части.");
ЗначениеЗаписи = Неопределено;
КонецЕсли;
Этот подход является наиболее рекомендуемым, поскольку он явно разделяет проверку существования свойства от попытки получить его значение, предотвращая ошибку "Поле объекта не обнаружено".
Установлено(Свойство) для проверки наличия и заполненности свойстваВ дополнение к проверке существования свойства с помощью Свойства.Получить(), мы можем также использовать метод Установлено(). Этот метод позволяет нам не только убедиться, что свойство существует в схеме XDTO, но и что оно имеет какое-либо значение, отличное от стандартного значения по умолчанию (например, null или Неопределено в контексте XDTO).
Как это работает:
СвойствоXDTO с помощью Свойства.Получить().СвойствоXDTO в метод Установлено(), вызванный у нашего основного объекта XDTO.Установлено() вернет Истина, если свойство существует и имеет установленное значение, и Ложь в противном случае.Это бывает полезно, когда нам нужно знать не просто о наличии поля, но и о том, что оно действительно было заполнено в XML-файле.
Установлено():
ИмяСвойства = "Запись";
ОбъектТЧ = тОбъектОбмена.ТабличнаяЧасть[1]; // Допустим, это ОбъектXDTO
// Шаг 1: Получаем объект СвойствоXDTO
СвойствоДляПроверки = ОбъектТЧ.Свойства.Получить(ИмяСвойства);
// Шаг 2: Проверяем существование и установленное значение
Если СвойствоДляПроверки <> Неопределено И ОбъектТЧ.Установлено(СвойствоДляПроверки) Тогда
// Свойство "Запись" существует и имеет установленное значение
ЗначениеЗаписи = ОбъектТЧ.Получить(ИмяСвойства);
Если ТипЗнч(ЗначениеЗаписи) = Тип("ОбъектXDTO") Тогда
Сообщить("Свойство " + ИмяСвойства + " существует, заполнено и является ОбъектXDTO.");
// Обработка как ОбъектXDTO
Иначе
Сообщить("Свойство " + ИмяСвойства + " существует, заполнено, но имеет другой тип: " + ТипЗнч(ЗначениеЗаписи));
// Обработка другого типа
КонецЕсли;
Иначе
// Свойство "Запись" либо не существует, либо не имеет установленного значения
Сообщить("Свойство " + ИмяСвойства + " не найдено или не заполнено.");
КонецЕсли;
Использование Установлено() добавляет дополнительный уровень контроля, позволяя нам не только проверять наличие поля, но и его содержательность.
Получить("ИмяСвойства") у объекта XDTOОбъект XDTO также имеет прямой метод Получить(), который позволяет получить значение свойства по его имени. Этот метод может быть удобен, но имеет свои особенности, которые мы должны учитывать.
Как это работает:
Получить() непосредственно у объекта XDTO, передавая имя свойства в виде строки.Неопределено.В нашей исходной проблеме было замечено, что тОбъектОбмена.ТабличнаяЧасть[1].Получить("Запись") вызывал ошибку, в то время как тОбъектОбмена.ТабличнаяЧасть[2].Получить("Запись") успешно возвращал ОбъектXDTO. Это подчеркивает, что поведение метода Получить() может зависеть от конкретной структуры XDTO и того, является ли свойство по схеме обязательным или опциональным, а также от наличия самого элемента. Поэтому, полагаться исключительно на Получить() без предварительной проверки может быть рискованно.
// Пример, который может вызвать ошибку, если свойство "Запись" отсутствует в тОбъектОбмена.ТабличнаяЧасть[1]
Попытка
ЗначениеЗаписи1 = тОбъектОбмена.ТабличнаяЧасть[1].Получить("Запись");
Если ТипЗнч(ЗначениеЗаписи1) = Тип("ОбъектXDTO") Тогда
Сообщить("Значение Записи1 успешно получено, тип: " + ТипЗнч(ЗначениеЗаписи1));
// Обработка
КонецЕсли;
Исключение ЭлементОшибка
Сообщить("Ошибка при получении свойства 'Запись' для элемента 1: " + ЭлементОшибка.Описание);
ЗначениеЗаписи1 = Неопределено;
КонецПопытки;
// Пример, который может работать, если свойство "Запись" существует в тОбъектОбмена.ТабличнаяЧасть[2]
Попытка
ЗначениеЗаписи2 = тОбъектОбмена.ТабличнаяЧасть[2].Получить("Запись");
Если ТипЗнч(ЗначениеЗаписи2) = Тип("ОбъектXDTO") Тогда
Сообщить("Значение Записи2 успешно получено, тип: " + ТипЗнч(ЗначениеЗаписи2));
КонецЕсли;
Исключение ЭлементОшибка
Сообщить("Ошибка при получении свойства 'Запись' для элемента 2: " + ЭлементОшибка.Описание);
ЗначениеЗаписи2 = Неопределено;
КонецПопытки;
Мы видим, что использование конструкции Попытка...Исключение может быть одним из способов обработки потенциальных ошибок при использовании прямого Получить(), но это менее элегантный и производительный подход по сравнению с предварительной проверкой через Свойства.Получить().
СписокXDTO)В нашем случае, тОбъектОбмена.ТабличнаяЧасть, скорее всего, является СписокXDTO. При работе с такими коллекциями полезно итерировать по их элементам и проверять каждый элемент по отдельности, так как их структура может быть неоднородной.
СписокXDTO:
Если ТипЗнч(тОбъектОбмена.ТабличнаяЧасть) = Тип("СписокXDTO") Тогда
Для Каждого СтрокаТЧ Из тОбъектОбмена.ТабличнаяЧасть Цикл
// Сначала убедимся, что текущий элемент сам является ОбъектXDTO, прежде чем пытаться получить его свойства
Если ТипЗнч(СтрокаТЧ) = Тип("ОбъектXDTO") Тогда
ИмяСвойстваДляПроверки = "Запись";
СвойствоЗаписьВСтроке = СтрокаТЧ.Свойства.Получить(ИмяСвойстваДляПроверки);
Если СвойствоЗаписьВСтроке <> Неопределено Тогда
// Свойство "Запись" существует в текущем элементе
ЗначениеЗаписи = СтрокаТЧ.Получить(ИмяСвойстваДляПроверки);
Если ТипЗнч(ЗначениеЗаписи) = Тип("ОбъектXDTO") Тогда
Сообщить("В текущем элементе табличной части найдено свойство '" + ИмяСвойстваДляПроверки + "', являющееся ОбъектXDTO.");
// Дальнейшая логика обработки вложенного ОбъектXDTO
Иначе
Сообщить("В текущем элементе табличной части найдено свойство '" + ИмяСвойстваДляПроверки + "', но оно имеет другой тип: " + ТипЗнч(ЗначениеЗаписи));
КонецЕсли;
Иначе
Сообщить("Свойство '" + ИмяСвойстваДляПроверки + "' отсутствует в текущем элементе табличной части.");
КонецЕсли;
Иначе
Сообщить("Элемент табличной части не является ОбъектXDTO, его тип: " + ТипЗнч(СтрокаТЧ));
КонецЕсли;
КонецЦикла;
Иначе
Сообщить("Переменная 'тОбъектОбмена.ТабличнаяЧасть' не является СпискомXDTO.");
КонецЕсли;
Этот подход обеспечивает максимальную гибкость и безопасность при работе с динамически изменяющимися структурами XML.
Неопределено. Например, если тОбъектОбмена или тОбъектОбмена.ТабличнаяЧасть могут быть Неопределено, проверяйте это до того, как пытаться обращаться к их элементам или свойствам.Неопределено.СписокXDTO), итерировать по ее элементам.ОбъектXDTO), использовать Свойства.Получить() для проверки наличия нужного свойства.Установлено() для проверки, что свойство имеет непустое значение.Следуя этим рекомендациям, мы значительно повысим надежность нашего кода при работе с объектами XDTO и сможем избежать досадных ошибок "Поле объекта не обнаружено", делая наши обработки XML-файлов более устойчивыми к изменениям во входящих данных. Также для предварительного контроля входящих файлов подойдёт обработка для валидации XML по схеме XSD.