Работа с XML-файлами через механизмы XDTO (XML Data Transfer Objects) является стандартом для современной платформы 1С:Предприятие 8.3. Однако начинающие разработчики часто сталкиваются с трудностями при попытке обработать данные, которые могут отсутствовать в файле или иметь пустые значения. В данной статье мы подробно разберем, как корректно проверять наличие свойств в объектах XDTO, как определять их заполненность и как эффективно искать существующие записи в базе данных, чтобы избежать дублирования.
Прежде чем приступать к написанию кода, проанализируем ситуацию. Когда мы читаем XML-файл с помощью фабрики XDTO, платформа создает иерархическую структуру объектов. Важно понимать, что обращение к реквизиту через точку, например Элемент.Телефоны, возвращает не строку и не число, а именно объект типа ОбъектXDTO или значение, типизированное согласно схеме XSD.
Если в XML-файле отсутствует тег или атрибут, прямое обращение к нему может вызвать исключение (ошибку), если это не разрешено схемой. Рассмотрим ситуацию, когда тег в файле присутствует, но он пустой: <Телефоны />. В этом случае 1С может интерпретировать его по-разному в зависимости от типа данных, указанного в пакете XDTO. Именно поэтому стандартные функции ПустаяСтрока() часто выдают ошибку: они ожидают строку, а получают сложный объект.
Для того чтобы безопасно работать с данными из XML, мы рекомендуем использовать метод Свойство(). Этот метод позволяет проверить, существует ли вообще такое поле в объекте, не вызывая аварийного завершения программы. Выясним, как это реализовать на практике.
Рассмотрим по шагам алгоритм проверки:
XDTO.Неопределено.ЗначениеЗаполнено() для проверки фактического содержания.
// Предположим, 'Элемент' — это наш ОбъектXDTO
ИмяСвойства = "Телефоны";
Если Элемент.Свойства().Получить(ИмяСвойства) <> Неопределено Тогда
ЗначениеИзXML = Элемент[ИмяСвойства];
// Проверяем, заполнено ли значение фактически
Если ЗначениеЗаполнено(ЗначениеИзXML) Тогда
НовыйКонтрагент.Телефоны = Строка(ЗначениеИзXML);
КонецЕсли;
КонецЕсли;
В данном примере мы используем обращение по индексу Элемент[ИмяСвойства], что позволяет писать более гибкий код. Обратите внимание на явное приведение к типу Строка(). Это "хороший тон" при работе с XDTO, так как позволяет избежать конфликтов типов при записи в реквизит справочника.
Вторая важная задача — проверка на существование записи в справочнике перед созданием новой. Рассмотрим ситуацию с поиском по ИНН. Автор вопроса пытался использовать метод НайтиПоРеквизиту(), но столкнулся с логической ошибкой в условии.
Проанализируем правильный подход к поиску. Метод НайтиПоРеквизиту() всегда возвращает ссылку. Если элемент не найден, возвращается пустая ссылка соответствующего типа. Поэтому проверка Если НайтиПоРеквизиту(...).Пустая() является ключевой.
// Получаем ИНН из объекта XDTO
ТекущийИНН = Строка(Элемент.ИНН);
// Выполняем поиск в справочнике Контрагенты
СсылкаНаСуществующий = Справочники.Контрагенты.НайтиПоРеквизиту("ИНН", ТекущийИНН);
Если Не СсылкаНаСуществующий.Пустая() Тогда
// Если нашли — пропускаем итерацию или обновляем данные
Сообщить("Контрагент с ИНН " + ТекущийИНН + " уже существует. Пропускаем.");
Продолжить;
КонецЕсли;
// Если не нашли — создаем новый объект
НовыйОбъект = Справочники.Контрагенты.СоздатьЭлемент();
// Заполнение реквизитов...
НовыйОбъект.Записать();
Если предполагается загрузка большого объема данных (тысячи строк), использование НайтиПоРеквизиту() в цикле может существенно замедлить работу системы, так как на каждой итерации будет происходить отдельное обращение к базе данных. Проанализируем более профессиональный подход — использование запросов.
Рассмотрим вариант, когда мы заранее проверяем наличие группы контрагентов. Однако для разовой загрузки или небольших файлов метод НайтиПоРеквизиту() вполне допустим, при условии, что реквизит "ИНН" в конфигураторе помечен как Индексировать. Без индексации поиск по справочнику превратится в полное сканирование таблицы, что недопустимо для производительности.
Объединим все полученные знания в единый алгоритм. Посмотрим на пример кода, который читает файл, проверяет поля на пустоту и ищет дубликаты.
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ПутьКФайлу);
// Читаем объект через фабрику XDTO
ДанныеЗагрузки = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
Для Каждого ТекущийОбъектXDTO Из ДанныеЗагрузки.Элементы Цикл
// 1. Поиск по уникальному идентификатору (ИНН)
ИНН_XDTO = "";
Если ТекущийОбъектXDTO.Свойства().Получить("ИНН") <> Неопределено Тогда
ИНН_XDTO = СокрЛП(Строка(ТекущийОбъектXDTO.ИНН));
КонецЕсли;
Если ПустаяСтрока(ИНН_XDTO) Тогда
Сообщить("В данных отсутствует ИНН, объект пропущен.");
Продолжить;
КонецЕсли;
СсылкаНаКонтрагента = Справочники.Контрагенты.НайтиПоРеквизиту("ИНН", ИНН_XDTO);
Если СсылкаНаКонтрагента.Пустая() Тогда
Объект1С = Справочники.Контрагенты.СоздатьЭлемент();
Объект1С.ИНН = ИНН_XDTO;
Иначе
// Если нужно обновлять существующие — получаем объект
Объект1С = СсылкаНаКонтрагента.ПолучитьОбъект();
КонецЕсли;
// 2. Проверка заполненности атрибутов (Адрес, Телефон)
// Используем вспомогательную логику для каждого поля
Если ТекущийОбъектXDTO.Свойства().Получить("Адрес") <> Неопределено Тогда
ЗначениеАдреса = Строка(ТекущийОбъектXDTO.Адрес);
Если ЗначениеЗаполнено(ЗначениеАдреса) Тогда
Объект1С.Адрес = ЗначениеАдреса;
КонецЕсли;
КонецЕсли;
Если ТекущийОбъектXDTO.Свойства().Получить("Телефоны") <> Неопределено Тогда
ЗначениеТелефона = Строка(ТекущийОбъектXDTO.Телефоны);
Если ЗначениеЗаполнено(ЗначениеТелефона) Тогда
Объект1С.Телефоны = ЗначениеТелефона;
КонецЕсли;
КонецЕсли;
// 3. Запись данных
Попытка
Объект1С.Записать();
Исключение
Сообщить("Ошибка при записи контрагента: " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
ЧтениеXML.Закрыть();
При работе с загрузкой данных из внешних источников следует помнить о нескольких критически важных аспектах:
Объект.ОбменДанными.Загрузка = Истина. Это отключит прикладные проверки в модуле объекта, которые могут помешать загрузке технических данных или замедлить процесс.НачатьТранзакцию() ... ЗафиксироватьТранзакцию()). Это не только ускорит запись, но и гарантирует целостность данных: если один объект запишется с ошибкой, вы сможете откатить все изменения.2023-10-25 автоматически станет типом Дата в 1С. Всегда проверяйте, какой тип возвращает фабрика, прежде чем использовать строковые функции.xsi:nil="true". Метод Свойство() помогает определить физическое наличие тега, а ЗначениеЗаполнено() — наличие в нем полезной информации.Таким образом, мы выяснили, что основной проблемой при работе с XDTO является непонимание типов данных. Объекты XDTO требуют внимательного обращения и использования встроенных методов метаданных (Свойства()) для обеспечения стабильной работы обмена данными.