При разработке интеграционных механизмов, обмене сообщениями или сохранении настроек разработчики часто сталкиваются с необходимостью быстро перевести объект платформы (например, строку, число или структуру) в XML-строку и восстановить его обратно. Однако простая попытка вызвать методы ЗаписатьXML и ПрочитатьXML нередко приводит к ошибкам вида «Ошибка преобразования данных XML» или сбоям модели XDTO. Разберем по шагам, почему возникают эти исключения и как правильно реализовать сериализацию и десериализацию данных.
Рассмотрим типовой сценарий, с которого часто начинаются эксперименты с сериализацией:
Функция ВXML(Строка) Экспорт
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
ЗаписатьXML(ЗаписьXML, Строка);
Возврат ЗаписьXML.Закрыть();
КонецФункции
Функция ИзXML(Стр) Экспорт
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(Стр);
Возврат ПрочитатьXML(ЧтениеXML);
КонецФункции
Вызов метода ПрочитатьXML(ЧтениеXML) в данном примере завершается аварийно. Выясним причину такого поведения. Дело в том, что процедура ЗаписатьXML(ЗаписьXML, Значение) принимает необязательный третий параметр — НазначениеТипаXML, значением по умолчанию для которого является НазначениеТипаXML.Неявное. При неявном назначении типа примитивные значения (строки, числа, булевы флаги) записываются в поток без атрибута схемы xsi:type. В результате в сформированной строке отсутствует информация о том, какой именно тип платформы был упакован в XML-узел. Когда функция ПрочитатьXML пытается восстановить значение, не имея подсказки в виде атрибута типа и без явного указания второго параметра, она не может сопоставить узел ни с одним типом данных и выбрасывает исключение.
Для устранения этой ошибки у нас есть два пути:
ПрочитатьXML(ЧтениеXML, Тип("Строка")). Этот вариант удобен, когда структура пакета строго фиксирована и тип данных заранее известен принимающей стороне.НазначениеТипаXML.Явное. В этом случае узел получит атрибут с указанием типа (например, xsi:type="xs:string"), и метод ПрочитатьXML сможет определить его автоматически без дополнительных параметров.В типовых конфигурациях (в том числе в Библиотеке стандартных подсистем) для упаковки произвольных сериализуемых значений в XML применяется объект СериализаторXDTO. Посмотрим на надежный и универсальный пример функций:
Функция ЗначениеВСтрокуXML(Значение) Экспорт
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
// Явно указываем сериализатору необходимость добавлять атрибут типа
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, Значение, НазначениеТипаXML.Явное);
Возврат ЗаписьXML.Закрыть();
КонецФункции
Функция ЗначениеИзСтрокиXML(СтрокаXML) Экспорт
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(СтрокаXML);
// Проверяем возможность десериализации и считываем объект
Возврат СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
КонецФункции
Параметр НазначениеТипаXML.Явное гарантирует, что внутри XML-разметки будет присутствовать описание типа XSD. Благодаря этому десериализатор безошибочно распознает тип и создаст соответствующий объект 1С при чтении.
Для повышения надежности чтения перед вызовом СериализаторXDTO.ПрочитатьXML рекомендуется выполнять проверку:
Если СериализаторXDTO.ВозможностьЧтенияXML(ЧтениеXML) Тогда
Возврат СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
КонецЕсли;
Обратите внимание: если XML-документ содержит служебный пролог (декларацию вида <?xml version="1.0" encoding="UTF-8"?>) или пробельные символы перед корневым элементом, чтению может потребоваться предварительное позиционирование на открывающий тег с помощью вызова ЧтениеXML.Прочитать().
Иногда при выполнении полностью корректного кода на мобильной платформе или в конфигурации с назначением «Мобильное приложение» возникает ошибка XDTO-модели. Проанализируем ситуацию.
В платформе «1С:Предприятие» контекст СериализаторXDTO тесно связан с внутренней фабрикой метаданных конфигурации (пакетом current-config). На мобильной платформе состав поддерживаемых типов данных ограничен по сравнению с десктопной версией. Если конфигурация разрабатывалась для настольного приложения, а затем в ее свойствах было изменено «Назначение использования» на «Мобильное приложение», может произойти рассинхронизация внутренней фабрики типов и кэша метаданных.
Сериализатор пытается обратиться к дескрипторам типов или свойствам, которые в усеченной мобильной схеме отсутствуют или повреждены, из-за чего выбрасывается исключение о неверном параметре метода XDTO.
Как исправить данное поведение:
.cf), загрузите ее заново в чистую информационную базу и повторно выставьте свойство «Мобильное приложение». Это принудительно перестроит внутренние фабрики XDTO под мобильный состав метаданных.Если ваша задача сводится исключительно к передаче базовых типов (строка, число, дата, булево, уникальный идентификатор), использовать связку ЗаписьXML / ЧтениеXML и фабрику XDTO не обязательно. Платформа предоставляет компактные функции:
Функция XMLСтрока(Значение) формирует текстовое строковое представление значения в формате XML без обертывания в XML-теги. Для обратного преобразования используется функция XMLЗначение(Тип, СтрокаXML):
// Преобразование в строковое представление XML
ТекстXML = XMLСтрока(ТекущаяДата());
// Восстановление значения требуемого типа
ИсходнаяДата = XMLЗначение(Тип("Дата"), ТекстXML);
Эти функции работают предельно быстро, не создают накладных расходов на создание объектов потокового чтения/записи и полностью изолированы от структуры метаданных конфигурации.
В современной разработке (особенно для мобильных клиентов и веб-сервисов) для обмена структурами и массивами предпочтительнее использовать ЗаписьJSON и ЧтениеJSON. Формат JSON компактнее XML, не требует передачи схем типов и обрабатывается платформой быстрее.