При работе с внешними данными в формате XML программисты 1С часто сталкиваются с механизмом XDTO (XML Data Transfer Objects). Это мощный инструмент, который позволяет представить структуру XML в виде удобного дерева объектов. Особенно часто это востребовано, когда реализуется простой обмен данными между базами 1С и приложениями. Однако иногда этот механизм ведет себя неочевидно: вместо ожидаемой пустой строки или значения Неопределено при чтении пустого тега программа возвращает строку «ОбъектXDTO». Это сбивает с толку и мешает корректному заполнению реквизитов справочников или табличных частей.
В данной статье мы разберем, почему так происходит, как правильно обрабатывать такие ситуации и какие альтернативные способы чтения данных существуют.
Для начала проанализируем ситуацию. Когда мы обращаемся к свойству объекта XDTO, 1С пытается вернуть значение в соответствии с описанием типа в схеме (XSD). Если в схеме элемент описан как ComplexType (сложный тип), 1С всегда инициализирует его как объект, даже если в самом XML-файле между тегами ничего нет. Чтобы лучше понимать структуру импортируемых данных, разработчики часто используют инструменты для конвертации схемы XSD в модель XDTO.
Таким образом, обращаясь к ФизЛицо.ИНН, вы получаете не содержимое тега, а сам объект управления этим элементом. Рассмотрим основные причины такого поведения:
ОбъектXDTO. При попытке вывести его в текстовое поле (например, в ячейку таблицы) срабатывает стандартное строковое представление объекта, которое и выглядит как «ОбъектXDTO».nillable="true". Если он установлен, а в XML передан атрибут xsi:nil="true", 1С должна возвращать Неопределено. Но если атрибут xsi:nil отсутствует, а тег пуст, создается объект.Самый быстрый и практичный способ, часто упоминаемый в практических справочниках разработчика 1С, — это проверка типа полученного значения перед его записью в базу данных. Мы можем проверить, является ли результат объектом XDTO, и если да — заменить его на пустое значение или Неопределено.
Рассмотрим пример кода, который решает эту задачу:
// Предположим, ФизЛицо — это прочитанный объект XDTO
НоваяСтрока = Объект.ТЧ_Данные.Добавить();
// Проверяем тип реквизита "Номер"
Если ТипЗнч(ФизЛицо.Номер) = Тип("ОбъектXDTO") Тогда
НоваяСтрока.Номер = ""; // Или Неопределено, в зависимости от логики
Иначе
НоваяСтрока.Номер = ФизЛицо.Номер;
КонецЕсли;
Используя сокращенную форму записи (тернарный оператор), мы можем сделать код более лаконичным:
НоваяСтрока.Номер = ?(ТипЗнч(ФизЛицо.Номер) = Тип("ОбъектXDTO"), "", ФизЛицо.Номер);
Этот подход надежно защищает ваши реквизиты от записи в них служебной строки «ОбъектXDTO».
Более методически верным способом работы с XDTO является проверка того, установлено ли значение свойства в принципе. Объект XDTO имеет встроенный метод СвойстваУстановлено(), который позволяет выяснить, содержит ли элемент данные.
Проанализируем этот подход:
Если ФизЛицо.СвойстваУстановлено("Номер") Тогда
// Обрабатываем значение, только если оно реально присутствует в XML
НоваяСтрока.Номер = ФизЛицо.Номер;
Иначе
НоваяСтрока.Номер = "";
КонецЕсли;
Важный нюанс: Если тег в XML присутствует (например, <Номер></Номер>), метод СвойстваУстановлено вернет Истина, так как узел существует, даже если он пустой. В этом случае проверка типа из первого решения остается более универсальной.
Если структура XML-файла очень простая или, наоборот, слишком избыточная, использование XDTO может быть неоправданно тяжелым. В таких случаях часто применяется выгрузка и загрузка данных XML с дополнительными опциями, позволяющая более гибко управлять процессом. Рассмотрим альтернативный вариант — использование объекта ЧтениеXML. Как показывают тесты производительности методов чтения XML, этот метод работает быстрее и потребляет меньше памяти, так как не строит дерево объектов.
Разберем пример реализации прямого чтения:
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ПутьКФайлу);
Пока Чтение.Прочитать() Цикл
Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента И Чтение.Имя = "Номер" Тогда
// Читаем содержимое следующего текстового узла
Чтение.Прочитать();
Если Чтение.ТипУзла = ТипУзлаXML.Текст Тогда
ЗначениеНомера = Чтение.Значение;
Иначе
ЗначениеНомера = ""; // Узел пуст
КонецЕсли;
КонецЕсли;
КонецЦикла;
В этом случае вы полностью контролируете процесс и гарантированно не получите никаких лишних объектов.
В процессе обсуждения была затронута еще одна важная техническая проблема: пространства имен XML и появление атрибута xmlns="" у дочерних элементов при записи XML. Это происходит, когда дочерние элементы «отвязываются» от пространства имен родителя.
Выясним причину: это связано с настройкой elementFormDefault в XSD-схеме.
elementFormDefault="unqualified", то только корневой элемент принадлежит пространству имен, а вложенные — нет. Чтобы это подчеркнуть, 1С добавляет xmlns="".Если вы создаете объекты программно через Фабрика.Создать(), всегда проверяйте, передаете ли вы правильный ТипОбъектаXDTO, который уже включает в себя нужное пространство имен.
Если ваша задача — просто прочитать данные, которые ранее были выгружены из другой базы 1С, наиболее эффективным методом будет Сериализатор XDTO. Аналогичным образом работает адаптивная выгрузка и загрузка данных XML, которая позволяет обмениваться данными даже между не полностью идентичными конфигурациями. Сериализатор автоматически преобразует типы XML в типы 1С (ссылки, числа, даты), корректно обрабатывая пустые значения.
Рассмотрим пример:
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ПутьКФайлу);
// Читаем объект целиком, 1С сама превратит пустые теги в пустые строки/ссылки
ОбъектДанных = СериализаторXDTO.ПрочитатьXML(Чтение);
Когда требуется перенести специфические данные, например, выгрузить и загрузить движения документа через XML, использование штатных механизмов сериализации значительно упрощает жизнь разработчику.
Подведем итог: Для быстрого исправления ошибки «ОбъектXDTO» используйте проверку ТипЗнч. Для глубокой и правильной работы с XML контролируйте настройки квалификации элементов в XSD-схемах и используйте методы проверки состояния свойств объекта XDTO.