Работа с механизмом XDTO (XML Data Transfer Objects) в 1С часто вызывает трудности у разработчиков, особенно на этапе импорта сторонних XSD-схем. Одной из самых распространенных проблем является ситуация, когда после импорта схемы ФабрикаXDTO.Тип() возвращает Неопределено, а при попытке прочитать XML возникают ошибки соответствия структуры. В этой статье мы подробно разберем, как избежать этих ловушек, правильно настроить пространства имен и обеспечить стабильную работу с данными.
Первая причина, по которой разработчики получают Неопределено при попытке получить тип, кроется в самой структуре XSD. Рассмотрим типичную ситуацию: в схеме определен элемент message, внутри которого сразу описан xs:complexType без имени. В терминах XSD это называется анонимным типом.
Проанализируем ситуацию: в платформе 1С метод ФабрикаXDTO.Тип(URI, "Имя") ищет именно именованный тип (complexType или simpleType), определенный в корне схемы. Если же в схеме определен только глобальный элемент (element), он попадает в категорию Свойства пакета XDTO, а не в типы.
Чтобы иметь возможность получить тип напрямую через фабрику, схему следует проектировать следующим образом:
<xs:complexType name="MessageType">
<xs:sequence>
<xs:element name="order" type="tns:OrderType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:element name="message" type="tns:MessageType"/>
Если вы не можете изменить входящую схему, необходимо использовать альтернативный способ получения типа через КорневыеСвойства пакета. Рассмотрим это подробнее в разделе реализации.
Пространства имен — это фундамент XML. Без четкого соответствия targetNamespace в схеме и xmlns в XML-документе, фабрика 1С не сможет сопоставить данные. Разберем ключевые атрибуты тега xs:schema:
Если в вашей схеме указан targetNamespace="http://my-site.ru/import", то во входящем XML-файле корневой тег обязательно должен содержать объявление этого пространства:
<message xmlns="http://my-site.ru/import">
<order>...</order>
</message>
Если сторонний сервис присылает «голый» XML без xmlns, 1С выдаст ошибку «Структура объекта не соответствует типу». В таких случаях нам придется программно модифицировать строку XML перед чтением.
Рассмотрим алгоритм действий, который гарантирует корректное чтение данных даже в сложных случаях.
Создайте новый Пакет XDTO в дереве конфигурации. Нажмите правой кнопкой мыши и выберите «Импорт схемы XML». Убедитесь, что после импорта заполнилось поле URI пространства имен. Если дерево объектов пакета пустое или содержит только свойства без типов — проверьте синтаксис XSD, особенно наличие префиксов xs: для стандартных типов (string, decimal). Для такой задачи подойдёт инструмент для конвертации схемы XSD в модель XDTO.
Поскольку наш message является свойством (элементом), а не типом, мы не можем вызвать ФабрикаXDTO.Тип(). Нам нужно обратиться к коллекции КорневыеСвойства. Рассмотрим пример кода:
// Определяем URI, который указан в пакете XDTO в конфигурации
ПространствоИмен = "http://losthost.online/plugin/instock";
// Получаем пакет из фабрики
Пакет = ФабрикаXDTO.Пакеты.Получить(ПространствоИмен);
// Находим описание корневого элемента "message"
СвойствоСообщения = Пакет.КорневыеСвойства.Получить("message");
// Из свойства извлекаем его тип (тот самый анонимный complexType)
ТипСообщения = СвойствоСообщения.Тип;
Если входящий XML не содержит объявлений пространств имен, мы можем добавить их вручную. Самый простой (хотя и «грубый») способ — замена строки. Более надежный — использование ПостроительDOM.
Разберем пример с программной коррекцией XML:
// Входящий текст XML без неймспейсов
ТекстXML = "<message><order>...</order></message>";
// Добавляем xmlns программно, если его нет
Если СтрНайти(ТекстXML, "xmlns") = 0 Тогда
ТекстXML = СтрЗаменить(ТекстXML, "<message", "<message xmlns=""" + ПространствоИмен + """");
КонецЕсли;
Чтение = Новый ЧтениеXML;
Чтение.УстановитьСтроку(ТекстXML);
Попытка
// Читаем объект, явно передавая полученный ранее тип
ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(Чтение, ТипСообщения);
// Теперь мы можем работать с данными
Для Каждого ТекущийЗаказ Из ОбъектXDTO.order Цикл
// Обработка заказа
КонецЦикла;
Исключение
Сообщить("Ошибка чтения XDTO: " + ОписаниеОшибки());
КонецПопытки;
Часто программисты сталкиваются с тем, что код Для Каждого... падает с ошибкой, если в XML пришел только один элемент (например, один order), и 1С восприняла его как ОбъектXDTO, а не как СписокXDTO.
Важное преимущество использования типов при чтении: Если вы передаете ТипСообщения в метод ПрочитатьXML(), платформа 1С заранее знает структуру из схемы XSD. Если в схеме указано maxOccurs="unbounded", то свойство всегда будет списком, даже если в XML передан всего один тег. Это избавляет от необходимости писать проверки ТипЗнч(Объект.Свойство) = Тип("СписокXDTO").
Проанализируем еще несколько нюансов, которые помогут в отладке:
ОбъектXDTO.Проверить(). Он позволяет выявить несоответствия типов (например, строку там, где ожидается число) до начала обработки данных.ФабрикаXDTO. Если же вы загружаете схему динамически из файла во время выполнения, создавайте локальную фабрику методом СоздатьФабрикуXDTO(ПутьКСхеме).СериализаторXDTO, но он гораздо менее гибкий при работе со сложными сторонними XSD, чем прямая работа с ФабрикаXDTO.Таким образом, успех импорта XSD зависит от трех факторов: точного указания targetNamespace, правильного извлечения типа из корневых свойств и обеспечения наличия xmlns во входящем XML-документе. Следуя этим правилам, вы сможете интегрировать 1С с любой внешней системой, использующей XML-обмен.