Как правильно инициализировать и заполнять объекты XDTO с помощью ФабрикиXDTO в 1С?

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

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

Создание примитивных и сложных типов XDTO

При работе с ФабрикаXDTO важно разделять примитивные типы данных (такие как xs:string, xs:integer, xs:dateTime из пространства имен http://www.w3.org/2001/XMLSchema) и сложные составные типы (ТипОбъектаXDTO).

Особенность метода Создать(): вызов ФабрикаXDTO.Создать("http://www.w3.org/2001/XMLSchema", "string") возвращает значение Неопределено. Это связано с тем, что метод предназначен исключительно для конструирования сложных объектов. Примитивные типы в 1С напрямую сопоставляются с базовыми типами встроенного языка (Строка, Число, Дата, Булево).

Рассмотрим, как правильно инициализировать реквизиты различных типов:


// Для примитивных типов присвоение выполняется напрямую базовыми значениями 1С:
ОбъектXDTO.ЧисловойРеквизит = 5;
ОбъектXDTO.СтроковыйРеквизит = "Тестовая строка";

// Для сложных составных типов необходимо сначала создать объект через ФабрикуXDTO:
ТипСложногоОбъекта = ФабрикаXDTO.Тип("http://www.sample-namespace.org", "ОченьСложныйТип");
ЗначениеСложногоТипа = ФабрикаXDTO.Создать(ТипСложногоОбъекта);

ЗначениеСложногоТипа.Реквизит1 = "Заполнение вложенных данных";
ЗначениеСложногоТипа.Реквизит2 = 100;

// Присваиваем созданный объект вложенному свойству родительского объекта:
ОбъектXDTO.СложныйРеквизит = ЗначениеСложногоТипа;

Рекурсивное заполнение глубоких иерархий XDTO

Когда требуется заполнить структуру с множественной вложенностью объектов и списков, вручную прописывать вызовы для каждого уровня неудобно. В таких случаях удобно использовать рекурсивную процедуру заполнения на основе пути к свойству (например, с использованием структуры или соответствия путей).

Проанализируем пример рекурсивной процедуры инициализации и заполнения свойств объекта XDTO:


&НаСервере
Процедура ЗаполнитьСвойстваОбъектаXDTOрек(ОбъектXDTO, тСоответствие)
    Для Каждого Эл Из тСоответствие Цикл
        ЛевоеИмяПоля = ?(Найти(Эл.Ключ, "/") <> 0, Лев(Эл.Ключ, Найти(Эл.Ключ, "/") - 1), Эл.Ключ);
        ПравыеИменаПолей = Прав(Эл.Ключ, СтрДлина(Эл.Ключ) - Найти(Эл.Ключ, "/"));
        
        Если ЛевоеИмяПоля = ПравыеИменаПолей Тогда
            // Элемент конечного уровня
            Если ТипЗнч(ОбъектXDTO[ЛевоеИмяПоля]) = Тип("СписокXDTO") Тогда
                ОбъектXDTO[ЛевоеИмяПоля].Добавить(Эл.Значение);
            Иначе
                ОбъектXDTO[ЛевоеИмяПоля] = Эл.Значение;
            КонецЕсли;
        Иначе
            // Промежуточный узел дерева
            Если ОбъектXDTO[ЛевоеИмяПоля] = Неопределено Тогда
                ТипВложенногоОбъекта = ОбъектXDTO.Тип().Свойства.Получить(ЛевоеИмяПоля).Тип;
                ОбъектXDTO[ЛевоеИмяПоля] = ФабрикаXDTO.Создать(ТипВложенногоОбъекта.URIПространстваИмен, ТипВложенногоОбъекта.Имя);
            КонецЕсли;
            
            ИменаПолей = Новый Соответствие;
            ИменаПолей.Вставить(ПравыеИменаПолей, Эл.Значение);
            
            ЗаполнитьСвойстваОбъектаXDTOрек(ОбъектXDTO[ЛевоеИмяПоля], ИменаПолей);
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Важный момент: обратите внимание на проверку Если ОбъектXDTO[ЛевоеИмяПоля] = Неопределено. Если объект промежуточного узла уже был создан на предыдущих итерациях цикла, повторно вызывать ФабрикаXDTO.Создать() нельзя, иначе ранее записанные свойства будут перезаписаны пустым объектом.

Десериализация XML: работы с атрибутами и содержимым узлов

Частая проблема при чтении XML с помощью вызова ФабрикаXDTO.ПрочитатьXML() возникает с тегами, которые содержат одновременно и атрибуты, и текстовое содержимое (например, <error code="001">Текст ошибки</error>).

Если считывание выполняется без подключенной XSD-схемы, платформа интерпретирует такой элемент как тип с открытой моделью. В этом случае атрибут доступен напрямую через точечную нотацию (Объект.error.code), а текстовое значение помещается в последовательность XDTO.

Получить значение текста из такого объекта можно следующими способами:

  1. Через последовательность объекта XDTO:

    Для доступа к тексту без схемы используется метод Последовательность():

    ТекстОшибки = ОбъектXDTO.error.Последовательность().ПолучитьТекст(0);
  2. Обход узлов через ЧтениеXML:

    Если разбор структуры выполняется последовательно через объект ЧтениеXML, то считывание атрибутов и содержимого разделяется по типам узлов:

    
    Пока ЧтениеXML.Прочитать() Цикл
        Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента И ЧтениеXML.Имя = "error" Тогда
            // Чтение атрибутов тега
            Если ЧтениеXML.КоличествоАтрибутов() > 0 Тогда
                Пока ЧтениеXML.ПрочитатьАтрибут() Цикл
                    ИмяАтрибута = ЧтениеXML.Имя;
                    ЗначениеАтрибута = ЧтениеXML.Значение;
                КонецЦикла;
            КонецЕсли;
        ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.Текст Тогда
            // Чтение текстового содержимого внутри тега
            ТекстЭлемента = ЧтениеXML.Значение;
        КонецЕсли;
    КонецЦикла;
    

Использование описанных подходов позволит избежать ошибок Неопределено при создании объектов XDTO и корректно обрабатывать XML-данные любой степени вложенности.

← На главную