Как прочитать XML из веб-сервиса SAP в 1С, если возникает ошибка Document is empty

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

Работа с веб-сервисами SAP часто преподносит сюрпризы 1С-разработчикам. Одной из самых коварных проблем является ситуация, когда стандартные механизмы платформы, такие как WSПрокси и ФабрикаXDTO, отказываются принимать ответ от сервера, выдавая фатальные ошибки разбора XML. Проанализируем типичную ситуацию: вы подключаетесь к сервису, вызываете метод, но вместо ожидаемого объекта XDTO получаете сообщение «Ошибка разбора XML: Document is empty» или «Структура объекта не соответствует типу». Разберем по шагам, почему это происходит и как заставить 1С корректно прочитать данные.

Причина 1: Экранирование спецсимволов (XML внутри XML)

Одной из главных архитектурных особенностей интеграции с SAP является передача данных в формате «Nested XML». Согласно спецификации WSDL, поле ответа может быть описано как простая строка (string), но фактически SAP передает в этой строке целый XML-документ. Чтобы этот вложенный документ не «сломал» структуру основного SOAP-пакета, сервер экранирует управляющие символы XML.

Рассмотрим ситуацию подробнее. Символ < превращается в &lt;, а символ > в &gt;. Когда 1С получает такой ответ через WSПрокси, она видит обычный текст. Если вы попытаетесь передать этот текст напрямую в метод ПрочитатьXML(), возникнет ошибка, так как с точки зрения парсера это не валидный XML-документ, а просто набор символов.

Решение: Нам необходимо выполнить обратное преобразование (Unescape). Проанализируем код, который поможет очистить полученную строку:


// Получаем ответ от сервиса как строку
ТекстОтвета = ОтветСервиса.ДокументВВидеСтроки;

// Заменяем экранированные последовательности на символы разметки
ТекстОтвета = СтрЗаменить(ТекстОтвета, "&lt;", "<");
ТекстОтвета = СтрЗаменить(ТекстОтвета, "&gt;", ">");
ТекстОтвета = СтрЗаменить(ТекстОтвета, "&amp;", "&");
ТекстОтвета = СтрЗаменить(ТекстОтвета, "&quot;", """");
ТекстОтвета = СтрЗаменить(ТекстОтвета, "&apos;", "'");

Только после такой замены ФабрикаXDTO сможет распознать структуру документа.

Причина 2: Ошибка Document is empty и невидимые символы

Если при вызове ЧтениеXML.УстановитьСтроку(ФайлXML) вы получаете ошибку «[1,1] Фатальная ошибка: Document is empty», хотя переменная ФайлXML явно содержит текст, проблема кроется в «мусоре» в начале строки. Проанализируем ситуацию: системы SAP при формировании ответа могут добавлять HTTP-заголовки, спецификации кодировки или BOM (Byte Order Mark).

Метод УстановитьСтроку() ожидает, что XML начнется немедленно. Если в первом байте находится невидимый символ или техническая информация SOAP-конверта, парсер выдает фатальную ошибку. Посмотрим, как очистить строку от лишних префиксов:


// Ищем начало тега XML
ПозицияНачала = Найти(ФайлXML, "<");
Если ПозицияНачала > 1 Тогда
    ЧистыйXML = Сред(ФайлXML, ПозицияНачала);
ИначеЕсли ПозицияНачала = 0 Тогда
    Сообщить("Строка не является XML документом!");
    Возврат;
КонецЕсли;

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

Причина 3: Несоответствие WSDL и реальности

Часто разработчики SAP меняют структуру ответа, не обновляя WSDL-описание на стороне сервиса. В этом случае WSПрокси в 1С пытается сопоставить пришедший XML со старой схемой XDTO и падает с ошибкой «Структура объекта не соответствует типу». Выясним, как обойти жесткую проверку типов.

Если автоматическое преобразование через WSПрокси не работает, нам стоит отказаться от использования типизированного ответа. Вместо того чтобы ожидать ОбъектXDTO, мы можем попробовать получить «сырые» данные. Однако в 1С при использовании WSПрокси это сделать сложно. Рассмотрим альтернативный путь — использование HTTPСоединение.

Разберем алгоритм работы через HTTPЗапрос:

  1. Формируем текстовое тело SOAP-запроса (его можно подсмотреть в SOAP UI).
  2. Отправляем POST-запрос на адрес сервиса.
  3. Получаем HTTPОтвет и извлекаем из него Тело как строку.
  4. С помощью строковых функций (Сред, Найти) вырезаем нужный нам фрагмент XML из SOAP-оболочки.
  5. Читаем полученный фрагмент через ФабрикаXDTO.ПрочитатьXML(), используя локальную фабрику, созданную на основе схемы (XSD).

Причина 4: Пространства имен (Namespaces)

Выясним, почему ФабрикаXDTO.ПрочитатьXML(Чтение) может выдавать ошибку, даже если XML валиден. Платформа 1С должна знать, к какому пакету XDTO относится читаемый файл. Если в файле указано пространство имен (атрибут xmlns), которого нет в текущей фабрике, чтение не удастся.

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


// Прокси.ФабрикаXDTO уже содержит все схемы из WSDL
Чтение = Новый ЧтениеXML;
Чтение.УстановитьСтроку(ЧистыйXML);

// Определяем тип, к которому нужно привести XML
ТипОбъекта = Прокси.ФабрикаXDTO.Тип("http://sap.com/xi/your_namespace", "ИмяТипа");

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

Практические советы по отладке

Для успешного решения проблем с XML-сервисами SAP рекомендуем выполнить следующие действия:

Резюмируя: ошибка Document is empty в 90% случаев означает, что вы пытаетесь скормить парсеру не чистый XML, а строку с техническим заголовком или экранированными символами. Очистка строки и приведение ее к стандартному виду XML-документа решают проблему в большинстве случаев.

← На главную