Ошибка несоответствия структуры XDTO при работе с WS-ссылкой: причины и способы решения

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

При интеграции 1С с внешними государственными или корпоративными системами (например, сервисы ЕПГУ, Россети и др.) через механизм WS-ссылок (SOAP), разработчики часто сталкиваются с ошибками валидации ответов. Одной из распространенных проблем является ситуация, когда метод веб-сервиса отрабатывает успешно, но 1С не может разобрать полученный XML-ответ, выдавая ошибку несоответствия структуры XDTO.

Разберем подробно природу этой ошибки, почему она возникает даже при визуально корректном ответе, и рассмотрим рабочие методы ее устранения на примере реальной задачи интеграции.

Симптомы проблемы и анализ ошибки

Рассмотрим типичный сценарий. Вы импортировали WSDL-описание сервиса в конфигурацию 1С как WS-ссылку. При вызове метода сервиса соединение устанавливается, запрос уходит, но при попытке получить результат возникает исключение.

Текст ошибки обычно выглядит следующим образом:


Ошибка преобразования данных XDTO: Чтение объекта типа: {URI_Пространства_Имен}ТипОбъекта
- [12,19] Проверка свойства 'ИмяСвойства1': форма: Элемент имя: {URI}ИмяСвойства1 тип: {URI}ТипСвойства
по причине:
Ошибка проверки данных XDTO: Структура объекта не соответствует типу: {URI_Пространства_Имен}ТипОбъекта
Не установлено значение одного из следующих свойств: ИмяСвойства2

В примере из обсуждения ошибка звучала так: Не установлено значение одного из следующих свойств: RequestId_EPGU. При этом, если посмотреть сырой XML-ответ через сниффер или отладчик, тег RequestId_EPGU в нем присутствует.

Почему возникает ошибка, если тег есть?

Корень проблемы кроется в строгом соответствии стандарту XML Schema (XSD), который использует 1С. В WSDL-описании сложные типы данных часто определяются через конструкцию sequence (последовательность).

Для парсера XDTO в 1С это означает жесткое правило: элементы внутри родительского тега должны следовать строго в том порядке, в котором они описаны в схеме.

Проанализируем ситуацию на примере:

  1. В схеме (WSDL) описано, что сначала должно идти поле RequestId_Portal, а за ним — RequestId_EPGU.
  2. Сервер (в данном случае "кривой" сервис поставщика) присылает ответ, где эти поля поменяны местами: сначала идет RequestId_EPGU.
  3. Парсер 1С начинает читать XML. Он ожидает увидеть RequestId_Portal.
  4. Вместо этого он встречает RequestId_EPGU.
  5. Парсер считает, что обязательное поле RequestId_Portal отсутствует или последовательность нарушена, и выбрасывает исключение.

Если бы в схеме использовалась конструкция all вместо sequence, порядок полей был бы неважен, но мы вынуждены работать с тем WSDL, который предоставляет поставщик услуг.

Варианты решения проблемы

Поскольку исправить сервис поставщика мы, как правило, не можем, рассмотрим способы обхода этой проблемы на стороне 1С.

Способ 1. Программное создание WS-Прокси с настройкой SSL (Рекомендуемый)

Часто проблема усугубляется некорректными ссылками внутри самого WSDL (например, ссылки на http вместо https) или проблемами с сертификатами. Наиболее надежный способ — создавать подключение программно, явно указывая параметры.

Рассмотрим пример кода, который решает проблему подключения и корректной обработки данных. Обратите внимание на использование защищенного соединения OpenSSL, что критично для государственных сервисов.


// Определение параметров подключения
// Эти данные берутся из документации к сервису или WSDL
URIПространстваИменСервиса = "http://адрес.пространства.имен/service"; // Уточните в WSDL
ИмяСервиса = "RequestServices";
ИмяПорта = "RequestServicesEndpoint";

// Настройка защищенного соединения
// OpenSSL необходим для корректной работы с https-сервисами
SSL = Новый ЗащищенноеСоединениеOpenSSL;

// Создание прокси программно на основе статической WS-ссылки
// WSСсылкаЕПГУ - это имя вашей WS-ссылки в дереве метаданных
Соединение = WSСсылки.WSСсылкаЕПГУ.СоздатьWSПрокси(
    URIПространстваИменСервиса,
    ИмяСервиса,
    ИмяПорта,
    , // Адрес WSDL (если отличается)
    , // Таймаут
    SSL
);

// Установка учетных данных, если требуются
Соединение.Пользователь = "UserLogin";
Соединение.Пароль = "UserPassword";

// Формирование параметра запроса через Фабрику XDTO
// Это позволяет создать объект, строго соответствующий схеме
ТипПараметра = Соединение.ФабрикаXDTO.Пакеты.Получить(URIПространстваИменСервиса).Получить("GetRequest");
КоличествоЗаявок = Соединение.ФабрикаXDTO.Создать(ТипПараметра);

// Заполнение свойств
КоличествоЗаявок.count = 1;

// Выполнение метода
Попытка
    Результат = Соединение.GetRequest(КоличествоЗаявок);
    // Результат уже будет объектом XDTO, который можно обходить
Исключение
    Сообщить("Ошибка вызова сервиса: " + ОписаниеОшибки());
КонецПопытки;

Способ 2. Локальная правка WSDL (Если порядок полей критичен)

Если программное создание прокси не помогает и ошибка Структура объекта не соответствует типу сохраняется из-за перепутанных полей, нам необходимо "обмануть" 1С, заставив ее ожидать поля в том порядке, в котором их присылает сервер.

Выполним следующие шаги:

  1. Сохраним WSDL-файл (и все связанные XSD схемы) на диск. Это можно сделать, открыв WSDL-ссылку в браузере и выбрав "Сохранить как".
  2. Откроем сохраненный файл в текстовом редакторе (Notepad++, VS Code).
  3. Найдем описание проблемного типа данных (поиск по имени типа из ошибки XDTO).
  4. Внутри тега <xs:sequence> или <xsd:sequence> вручную поменяем местами строки с описанием элементов RequestId_EPGU и RequestId_Portal (или других проблемных полей).
  5. В конфигураторе 1С в свойствах WS-ссылки установим флажок "Импортировать из файла" и укажем путь к нашему исправленному локальному файлу.

После этого платформа сгенерирует внутреннюю схему, соответствующую реальному ответу сервера, и ошибка исчезнет.

Способ 3. Отказ от WS-ссылок в пользу HTTP-запросов

В самых сложных случаях, когда структура ответа меняется динамически или содержит грубые нарушения стандартов XML, использование механизма WS-ссылок и XDTO становится невозможным. В этом случае переходим на низкоуровневую работу.

Рассмотрим алгоритм действий:

  1. Формируем тело SOAP-запроса (XML-конверт) вручную как текст.
  2. Отправляем его через объект HTTPСоединение методом POST.
  3. Получаем ответ как строку текста.
  4. Парсим ответ, используя объект ЧтениеXML или ОбъектDOM.

При использовании ОбъектDOM мы можем искать нужные узлы по именам тегов, игнорируя их порядок следования. Это самый надежный, но и самый трудоемкий способ.

Рекомендации по диагностике

Если вы столкнулись с подобной ошибкой, воспользуйтесь следующими инструментами для анализа:

← На главную