При интеграции 1С с внешними веб-сервисами (особенно государственными информационными системами, такими как РУЗДИ ФНП) программисты часто сталкиваются с парадоксальной ситуацией: сторонние инструменты (например, Fiddler или SoapUI) показывают, что сервер вернул корректный HTTP 200 OK с заполненным телом, но 1С выбрасывает исключение: Ошибка проверки данных XDTO: Значение не соответствует образцу. Рассмотрим подробнее, почему это происходит и как решить проблему различными способами.
Разберем ситуацию на примере. При вызове метода веб-сервиса uploadNotificationPackage платформа 1С получает XML-ответ. В этом ответе присутствует элемент registrationId, который в схеме XSD описан как guidType. Тип guidType обычно имеет наложенное ограничение (фасет) в виде регулярного выражения, описывающего формат GUID (например, [0-9a-fA-F]{8}-...).
Проблема заключается в том, что сервер (часто реализованный на PHP) возвращает ответ в следующем виде:
<v1:registrationId></v1:registrationId>
Проанализируем этот фрагмент с точки зрения XDTO. В схеме для этого поля указано minOccurs="0". Это означает, что тег может отсутствовать в XML-документе вовсе. Однако, если тег присутствует, его содержимое обязано соответствовать типу данных. Пустая строка внутри тега не является валидным GUID и не проходит проверку по шаблону (паттерну). 1С, будучи строго типизированной системой в плане работы с XDTO, прерывает выполнение операции с ошибкой, так как не может десериализовать «пустоту» в объект заданного типа.
Использование объекта WSПрокси удобно, но оно не оставляет возможности вмешаться в процесс получения «сырых» данных до того, как их начнет парсить внутренний механизм 1С. Если веб-сервис присылает технически некорректные данные (пустые теги вместо их отсутствия), наиболее надежным решением будет переход на использование HTTPСоединение.
Рассмотрим по шагам, как реализовать этот подход:
ЗаписьXML и ФабрикаXDTO.HTTPСоединение.Посмотрим на пример реализации очистки и чтения данных:
// 1. Отправка запроса и получение ответа
ЗаголовокHTTP = Новый Соответствие;
ЗаголовокHTTP.Вставить("Content-Type", "text/xml;charset=utf-8");
ЗаголовокHTTP.Вставить("SOAPAction", "http://fciit.ru/eis2/ruzdi/uploadNotificationPackageService");
Соединение = Новый HTTPСоединение("ruzditest.eisnot.ru", 8280);
ЗапросHTTP = Новый HTTPЗапрос("/services/ruzdiUploadNotificationPackageService_v1_0", ЗаголовокHTTP);
ЗапросHTTP.УстановитьТелоИзСтроки(ТекстSOAPЗапроса);
ОтветHTTP = Соединение.ОтправитьДляОбъекта(ЗапросHTTP);
ТекстОтвета = ОтветHTTP.ПолучитьТелоИзСтроки();
// 2. Очистка "проблемных" пустых тегов
// Если сервис присылает пустой registrationId, 1С не сможет его прочитать как GUID.
// Удаляем этот тег из строки перед парсингом.
ТекстОтвета = СтрЗаменить(ТекстОтвета, "<v1:registrationId></v1:registrationId>", "");
// 3. Чтение очищенного XML через Фабрику XDTO
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(ТекстОтвета);
// Пропускаем конверт SOAP до тела сообщения
ЧтениеXML.ПерейтиКСодержимому();
Пока ЧтениеXML.Прочитать() Цикл
Если ЧтениеXML.Имя = "uploadNotificationPackageResponse" И ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
ДанныеОтвета = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML, ФабрикаXDTO.Тип("http://fciit.ru/eis2/ruzdi/uploadNotificationPackageService/v1_0", "uploadNotificationPackageResponseType"));
Прервать;
КонецЕсли;
КонецЦикла;
Если вы хотите продолжать использовать WSПрокси, можно попытаться обмануть механизм валидации, подменив схему данных. Выясним причину: 1С берет схему по ссылке ?wsdl или ?xsd. В этой схеме тип guidType жестко ограничен. Если мы создадим свое WSОпределение на основе локального файла схемы, в котором мы ослабим требования к этому типу, ошибка исчезнет.
Разберем, что нужно изменить в схеме .xsd:
guidType.xs:string без фасетов.Пример правки в XSD:
<!-- Было -->
<xsd:simpleType name="guidType">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-..." />
</xsd:restriction>
</xsd:simpleType>
<!-- Стало (упрощенно) -->
<xsd:simpleType name="guidType">
<xsd:restriction base="xsd:string" />
</xsd:simpleType>
После этого при создании WSПрокси необходимо указывать путь к локальному модифицированному файлу WSDL, который, в свою очередь, ссылается на локальную модифицированную схему XSD.
Проанализируем еще один вариант. Метод ПрочитатьXML() у объекта ФабрикаXDTO имеет возможность работать без явного указания типа, если в XML-документе указаны типы через xsi:type. Однако в случае с SOAP-ответами это редко помогает, так как 1С все равно сверяется с загруженной моделью XDTO.
Тем не менее, если мы используем ручное чтение через ЧтениеXML, мы можем извлекать значения узлов напрямую, не преобразуя весь ответ в объект XDTO. Это избавляет от ошибок валидации, но лишает нас удобства обращения к полям через точку (например, Объект.registrationId).
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(ТекстОтвета);
Пока ЧтениеXML.Прочитать() Цикл
Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
Если ЧтениеXML.ЛокальноеИмя = "message" Тогда
ТекстСообщения = ЧтениеXML.ПрочитатьСодержимое();
Сообщить("Результат от сервиса: " + ТекстСообщения);
КонецЕсли;
КонецЕсли;
КонецЦикла;
Для того чтобы точно определить, какой именно узел вызывает проблему, всегда используйте Fiddler. Обращайте внимание на следующие моменты:
text/xml).<tag/> или <tag></tag> в полях, которые помечены в схеме как date, dateTime, guid или int.В случае с сервисом РУЗДИ, код ошибки 13 («Ошибка разбора/сохранения документа пакета») часто сопровождается именно такими «грязными» XML-ответами. Сервер сообщает о бизнес-ошибке, но при этом формирует технически невалидную структуру для некоторых полей. В таких условиях только ручная обработка через HTTPСоединение и СтрЗаменить гарантирует стабильную работу интеграции.
Подводя итог, отметим, что XDTO в 1С — это мощный, но крайне строгий инструмент. При работе с внешними системами, которые не строго соблюдают собственные WSDL-описания, программисту 1С следует быть готовым к переходу на низкоуровневую работу с HTTP и XML.