Как разобрать XML-ответ от сервисов РЖД с помощью XDTO-пакета, если возникает ошибка структуры

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

Работа с внешними веб-сервисами, особенно такими сложными, как системы РЖД (сервисы SIW ПКТБ ЦКИ), часто преподносит сюрпризы при попытке использовать механизмы XDTO. Типичная ситуация: вы загрузили XSD-схему, создали XDTO-пакет, написали код для чтения XML, но система выдает ошибку: «Структура объекта не соответствует типу». В этой статье мы подробно разберем, почему это происходит и как заставить 1С корректно обрабатывать такие данные.

Проблема: Почему XDTO выдает ошибку на этапе чтения

Основная причина заключается в том, что механизм XDTO в 1С крайне строго следует описанной схеме. Если в пришедшем XML есть хотя бы малейшее отклонение от XSD — другой порядок полей, лишний атрибут, отсутствие обязательного элемента или неверный формат даты — метод ФабрикаXDTO.ПрочитатьXML() «спотыкается» и выбрасывает исключение. Рассмотрим ситуацию на примере «Справки №14» (технический паспорт вагона).

Проанализируем типичный код, который вызывает ошибку:


ЧтениеXML = Новый ЧтениеXML;        
ЧтениеXML.УстановитьСтроку(ТекстОтветаXML);
// Попытка получить тип из пакета
ТипЗначенияXDTO = ФабрикаXDTO.Тип("http://service.siw.pktbcki.rzd/", "reference14ASUResponse");

Попытка
    // Здесь происходит ошибка структуры
    ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML, ТипЗначенияXDTO);
Исключение
    Сообщить(ОписаниеОшибки());
КонецПопытки;

Решение 1: Проверка корневого элемента и соответствия типа

Первым делом проанализируем структуру самого XML. Часто разработчики пытаются прочитать ответ, используя тип Response (обертку), в то время как в переменной уже содержится само «тело» ответа. Если ваш XML начинается сразу с тега <reference14ASU>, то и тип в методе Тип() нужно указывать именно этот, а не reference14ASUResponse. 1С не сможет сопоставить вложенный элемент корневому, если они не совпадают в иерархии схемы.

Решение 2: Проблема «пустых» пространств имен (Namespaces)

В сервисах РЖД часто встречается специфика: корневой элемент имеет пространство имен (например, http://service.siw.pktbcki.rzd/), а вложенные теги, такие как row, в XML идут без префиксов. Если в вашем XDTO-пакете для свойства row установлена форма «Элемент» (Qualified), 1С будет ожидать, что каждый тег row будет принадлежать пространству имен. Если же сервер присылает их «голыми», возникнет ошибка соответствия.

Что нужно сделать:

  1. Откройте ваш XDTO-пакет в конфигураторе.
  2. Найдите свойство row (или аналогичные повторяющиеся элементы).
  3. Проверьте свойство «Форма». Если там стоит «Квалифицированный», попробуйте изменить на «Неуказанный» или проверьте глобальную настройку схемы elementFormDefault.

Решение 3: Обработка некорректных форматов дат

Это самая коварная причина. Стандарт XML требует, чтобы даты передавались в формате YYYY-MM-DDThh:mm:ss. Однако системы РЖД нередко возвращают даты в «человеческом» виде: 25.05.2023 12:00:00. Если в вашей XSD-схеме поле DATE_KON помечено типом xs:dateTime, 1С не сможет преобразовать эту строку в дату и забракует весь объект.

Разберем, как это обойти:

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

Решение 4: Чтение без указания строгого типа (AnyType)

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


ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(ТекстОтветаXML);

// Читаем без явного указания типа
ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);

// Теперь мы можем обходить свойства через цикл
Для каждого СтрокаДанных Из ОбъектXDTO.row Цикл
    Сообщить(СтрокаДанных.NOM_VAG);
КонецЦикла;

В этом случае, если 1С не найдет точного соответствия типа в пакете, она создаст ОбъектXDTO с типом AnyType. Вы сможете обращаться к его свойствам, но помните, что все значения могут быть представлены как строки, и вам придется контролировать типы данных самостоятельно.

Решение 5: Использование построителя DOM

Если XDTO категорически отказывается принимать XML из-за специфических заголовков или ошибок в самой схеме поставщика, воспользуемся проверенным «ручным» способом через ПостроительDOM. Это позволит нам не зависеть от жесткости XDTO-пакетов.

Рассмотрим пример реализации:


ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(ТекстОтветаXML);
Построитель = Новый ПостроительDOM;
ДокументDOM = Построитель.Прочитать(ЧтениеXML);

// Выбираем все узлы "row"
УзлыRow = ДокументDOM.ПолучитьЭлементыПоИмени("row");

Для каждого Узел Из УзлыRow Цикл
    // Читаем конкретное значение внутри узла
    Для каждого ДочернийУзел Из Узел.ДочерниеУзлы Цикл
        Если ДочернийУзел.ИмяУзла = "NOM_VAG" Тогда
            НомерВагона = ДочернийУзел.ТекстовоеСодержимое;
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

Советы по отладке

Проанализируем еще несколько важных моментов, которые помогут вам при разборе сложных пакетов:

  1. Порядок полей: XDTO в режиме sequence требует, чтобы поля шли строго в том порядке, в котором они описаны в XSD. Если сервер РЖД поменял поля местами, 1С выдаст ошибку. В схеме можно заменить xs:sequence на xs:all, если вы редактируете пакет вручную.
  2. Анализ через SoapUI: Всегда проверяйте «сырой» ответ от сервиса в сторонних утилитах. Это поможет увидеть, какие именно теги и пространства имен приходят на самом деле, и сравнить их с тем, что описано в конфигураторе.
  3. Сериализатор XDTO: Если вы получили объект, но не можете понять его структуру, используйте СериализаторXDTO для преобразования данных в привычные типы 1С, но это работает только если объект успешно прошел валидацию.

Подведем итог: Ошибка структуры в XDTO — это не приговор, а сигнал о несоответствии. Либо упростите требования схемы (заменив типы на строки и убрав строгий порядок), либо используйте более гибкие методы чтения, такие как DOM или чтение без указания типа. Выбор зависит от того, насколько стабилен формат данных от внешнего поставщика.

← На главную