Работа с механизмом XDTO в платформе 1С:Предприятие часто вызывает вопросы у разработчиков, особенно при первой встрече со сложными иерархическими структурами XML, веб-сервисами и десериализацией данных. Разберем основные нюансы инициализации примитивных и сложных типов 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, тСоответствие)
Для Каждого Эл Из тСоответствие Цикл
ЛевоеИмяПоля = ?(Найти(Эл.Ключ, "/") <> 0, Лев(Эл.Ключ, Найти(Эл.Ключ, "/") - 1), Эл.Ключ);
ПравыеИменаПолей = Прав(Эл.Ключ, СтрДлина(Эл.Ключ) - Найти(Эл.Ключ, "/"));
Если ЛевоеИмяПоля = ПравыеИменаПолей Тогда
// Элемент конечного уровня
Если ТипЗнч(ОбъектXDTO[ЛевоеИмяПоля]) = Тип("СписокXDTO") Тогда
ОбъектXDTO[ЛевоеИмяПоля].Добавить(Эл.Значение);
Иначе
ОбъектXDTO[ЛевоеИмяПоля] = Эл.Значение;
КонецЕсли;
Иначе
// Промежуточный узел дерева
Если ОбъектXDTO[ЛевоеИмяПоля] = Неопределено Тогда
ТипВложенногоОбъекта = ОбъектXDTO.Тип().Свойства.Получить(ЛевоеИмяПоля).Тип;
ОбъектXDTO[ЛевоеИмяПоля] = ФабрикаXDTO.Создать(ТипВложенногоОбъекта.URIПространстваИмен, ТипВложенногоОбъекта.Имя);
КонецЕсли;
ИменаПолей = Новый Соответствие;
ИменаПолей.Вставить(ПравыеИменаПолей, Эл.Значение);
ЗаполнитьСвойстваОбъектаXDTOрек(ОбъектXDTO[ЛевоеИмяПоля], ИменаПолей);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Важный момент: обратите внимание на проверку Если ОбъектXDTO[ЛевоеИмяПоля] = Неопределено. Если объект промежуточного узла уже был создан на предыдущих итерациях цикла, повторно вызывать ФабрикаXDTO.Создать() нельзя, иначе ранее записанные свойства будут перезаписаны пустым объектом.
Частая проблема при чтении XML с помощью вызова ФабрикаXDTO.ПрочитатьXML() возникает с тегами, которые содержат одновременно и атрибуты, и текстовое содержимое (например, <error code="001">Текст ошибки</error>).
Если считывание выполняется без подключенной XSD-схемы, платформа интерпретирует такой элемент как тип с открытой моделью. В этом случае атрибут доступен напрямую через точечную нотацию (Объект.error.code), а текстовое значение помещается в последовательность XDTO.
Получить значение текста из такого объекта можно следующими способами:
Для доступа к тексту без схемы используется метод Последовательность():
ТекстОшибки = ОбъектXDTO.error.Последовательность().ПолучитьТекст(0);
ЧтениеXML:
Если разбор структуры выполняется последовательно через объект ЧтениеXML, то считывание атрибутов и содержимого разделяется по типам узлов:
Пока ЧтениеXML.Прочитать() Цикл
Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента И ЧтениеXML.Имя = "error" Тогда
// Чтение атрибутов тега
Если ЧтениеXML.КоличествоАтрибутов() > 0 Тогда
Пока ЧтениеXML.ПрочитатьАтрибут() Цикл
ИмяАтрибута = ЧтениеXML.Имя;
ЗначениеАтрибута = ЧтениеXML.Значение;
КонецЦикла;
КонецЕсли;
ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.Текст Тогда
// Чтение текстового содержимого внутри тега
ТекстЭлемента = ЧтениеXML.Значение;
КонецЕсли;
КонецЦикла;
Использование описанных подходов позволит избежать ошибок Неопределено при создании объектов XDTO и корректно обрабатывать XML-данные любой степени вложенности.