При интеграции 1С с внешними веб-сервисами часто возникает необходимость передать внутри XML-запроса неэкранированный фрагмент данных или вложенный XML-документ, обернутый в секцию CDATA. Однако при использовании стандартного вызова веб-сервисов через WSПрокси и фабрику XDTO разработчики сталкиваются с тем, что платформа автоматически экранирует спецсимволы или выдает ошибку о синтаксической некорректности XML.
В этой статье мы подробно проанализируем причину возникновения этой проблемы и разберем правильные способы передачи данных в формате CDATA из 1С.
Рассмотрим, почему обычное присвоение строки с блоком CDATA свойству объекта XDTO не дает нужного результата. В стандарте XML Schema (XSD) не существует отдельного типа данных для CDATA — с точки зрения схемы это обычная строка. Когда мы присваиваем свойству объекта XDTO строковое значение, содержащее <![CDATA[...]]>, механизм сериализации XDTO выполняет автоэкранирование служебных символов XML. В результате символы < и > превращаются в < и >, а внешняя система получает экранированный текст вместо блока CDATA.
Если же попытаться передать такую строку без правильной обработки структуры, платформа 1С на этапе валидации или отправки может выдать ошибку с указанием на то, что вместо символа ! ожидает разделитель <.
Если схема XSD допускает смешанное содержимое (mixed content) у элемента, для манипуляции с открытым текстом или специальными фрагментами в объектах XDTO используется механизм последовательностей и служебное свойство __content.
Проанализируем пример работы с последовательностью объекта XDTO:
// Получаем объект последовательности из объекта XDTO
Последовательность = ОбъектXDTO.Последовательность();
// Добавляем текст в специальное свойство __content
Последовательность.Добавить(ОбъектXDTO.Свойства().Получить("__content"), ТекстXML);
Использование свойства __content и вызова Последовательность() позволяет управлять записью неэкранированного текста на уровне объекта XDTO, если это поддерживается моделью типа.
Если встроенная сериализация WSПрокси заменяет спецсимволы на сущности XML, самым надежным способом является явная сборка XML-документа с помощью объекта ЗаписьXML.
У объекта ЗаписьXML есть специализированный метод ЗаписатьСекциюCDATA(), который формирует корректный блок без экранирования входящих в него тегов. Рассмотрим пример создания такого документа:
Запись = Новый ЗаписьXML;
Запись.УстановитьСтроку("UTF-8");
Запись.ЗаписатьОбъявлениеXML();
Запись.ЗаписатьНачалоЭлемента("SEATS");
// Формируем текст для вставки в CDATA
ТекстData = "<SEAT><GOODS_TYPE_ID>2</GOODS_TYPE_ID></SEAT>";
// Записываем секцию CDATA
Запись.ЗаписатьСекциюCDATA(ТекстData);
Запись.ЗаписатьКонецЭлемента(); // SEATS
РезультатXML = Запись.Закрыть();
Также при наличии готовой строки, содержащей готовый сформированный блок, можно применить метод ЗаписатьБезОбработки(), который выгружает переданный фрагмент в XML-поток без любых синтаксических изменений.
Если обработка структуры выполняется в памяти в виде дерева узлов, можно использовать объект ДокументDOM и его метод СоздатьСекциюCDATA().
Разберем по шагам создание CDATA-узла:
ДокументDOM = Новый ДокументDOM;
КорневойУзел = ДокументDOM.СоздатьЭлемент("SEATS");
ДокументDOM.ВставитьПеред(КорневойУзел, Неопределено);
// Создаем секцию CDATA
УзелCDATA = ДокументDOM.СоздатьСекциюCDATA(ТекстЗапроса);
КорневойУзел.СвязатьУзел(УзелCDATA);
// Записываем DOM в строку
Запись = Новый ЗаписьXML;
Запись.УстановитьСтроку();
ЗаписьDOM = Новый ЗаписьDOM;
ЗаписьDOM.Записать(ДокументDOM, Запись);
Результат = Запись.Закрыть();
В случаях, когда сторонний веб-сервис строго требует наличие секции CDATA внутри SOAP-конверта, а высокоуровневый `WSПрокси` заменяет спецсимволы сущностями, необходимо перейти на прямую отправку SOAP-запроса через HTTP.
Рассмотрим алгоритм реализации:
ЗаписьXML (применяя ЗаписатьСекциюCDATA()) или через текстовый шаблон.HTTPСоединение и подготавливаем HTTPЗапрос.Content-Type (например, text/xml; charset=utf-8) и заголовок SOAPAction.POST и обрабатываем полученный ответ сервера.Комбинируя объект ЗаписьXML и прямой HTTP-вызов, вы сможите гарантировать передачу секций CDATA в исходном виде без искажения данных платформой 1С.