При разработке сложных интеграций или сохранении промежуточных данных в 1С:Предприятии часто возникает необходимость упаковать объект XDTO в текстовую строку (XML) для хранения в реквизите документа или справочника, а затем восстановить его обратно в виде полноценного объекта. Однако разработчики часто сталкиваются с проблемой: при чтении XML объект теряет свой исходный тип и превращается в универсальный anyType, что делает невозможным его дальнейшее использование в рамках пакета XDTO. Рассмотрим подробно, почему это происходит и как правильно реализовать процесс сериализации и десериализации.
Разберем ситуацию на примере кода, представленного в обсуждении. При записи объекта используется метод ЗаписатьXML, где в качестве параметров передаются сама запись, объект данных и пространство имен. Однако один из ключевых параметров — ЛокальноеИмя — часто оставляется пустым. Проанализируем, к чему это приводит.
Когда мы вызываем ФабрикаXDTO.ЗаписатьXML(ЗаписьXML, ДанныеXDTO) без указания локального имени, платформа пытается самостоятельно определить имя тега. Если ДанныеXDTO созданы на основе ТипаОбъектаXDTO (ComplexType), а не на основе конкретного Элемента схемы, система не «знает», каким тегом обернуть данные. В результате в XML-файле появляется корень anyType.
Ситуация усугубляется использованием параметра НазначениеТипаXML.Явное. В этом случае 1С принудительно записывает в XML атрибут xsi:type="xs:anyType". При последующем чтении, даже если вы попытаетесь указать фабрике ожидаемый тип, атрибут xsi:type внутри самого XML будет иметь приоритет, и вы получите объект anyType, который не подходит для вставки в строго типизированные коллекции.
Для того чтобы объект сохранил свою структуру и тип, необходимо явно указывать имя корневого элемента при записи. Давайте пересмотрим подход к сохранению объекта.
Рассмотрим пошагово правильный алгоритм записи:
// 1. Подготовка записи XML
ЗаписьXML = Новый ЗаписьXML();
ЗаписьXML.УстановитьСтроку();
// 2. Определение параметров записи
// Указываем конкретное имя тега, которое соответствует вашей схеме (например, "Документ")
ЛокальноеИмя = "Документ";
ПространствоИмен = "urn:1C.ru:commerceml_3";
// Важно: используем НазначениеТипаXML.Неявное, чтобы избежать жесткой привязки к anyType в атрибутах
МояФабрикаXDTO.ЗаписатьXML(ЗаписьXML, ДанныеXDTO, ЛокальноеИмя, ПространствоИмен, , НазначениеТипаXML.Неявное);
ЗначениеXML = ЗаписьXML.Закрыть();
В данном примере мы явно задали имя узла Документ. Теперь при чтении этого XML платформа сможет сопоставить структуру с метаданными из пакета XDTO.
При чтении XML-строки из реквизита документа недостаточно просто вызвать метод ПрочитатьXML. Чтобы гарантированно получить объект нужного типа, его необходимо передать вторым параметром в метод фабрики. Выясним, как это сделать правильно:
// 1. Подготовка чтения
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(СтрокаИзРеквизита);
// 2. Получение типа из фабрики
ТипДокументXDTO = МояФабрикаXDTO.Тип("urn:1C.ru:commerceml_3", "Документ");
// 3. Чтение с типизацией
// Передача типа вторым параметром заставляет фабрику интерпретировать XML именно как этот тип
Попытка
XDTOДокумент = МояФабрикаXDTO.ПрочитатьXML(ЧтениеXML, ТипДокументXDTO);
Исключение
Сообщить("Ошибка чтения XDTO: " + ОписаниеОшибки());
КонецПопытки;
Именно связка Явное локальное имя при записи + Передача типа при чтении позволяет избежать ошибки Несоответствие типов XDTO.
Если ваша задача — сохранить объект XDTO внутри одной и той же информационной базы для внутреннего использования (например, кэширование или отложенная обработка), более надежным и простым инструментом может выступить СериализаторXDTO. В отличие от базовой фабрики, сериализатор умеет работать с объектами 1С более нативно.
Проанализируем пример использования сериализатора:
// Запись
ЗаписьXML = Новый ЗаписьXML();
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ДанныеXDTO);
СтрокаXML = ЗаписьXML.Закрыть();
// Чтение
ЧтениеXML = Новый ЧтениеXML();
ЧтениеXML.УстановитьСтроку(СтрокаXML);
ВосстановленныйОбъект = СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
Важное ограничение: этот метод идеально работает, если типы определены в конфигурации или если вы используете стандартную фабрику XDTO. Если же вы работаете с внешней схемой через свою созданную фабрику, лучше придерживаться методов, описанных в Решении №1 и №2.
Рассмотрим несколько нюансов, которые могут повлиять на результат:
anyType.elementFormDefault. Если она установлена в unqualified, то дочерние элементы XML не будут иметь префикса пространства имен. В этом случае при чтении обязательно нужно указывать тип, иначе фабрика не поймет, к какому описанию относятся эти «безымянные» поля.ХранилищеЗначения. Это позволит не только сжимать данные, но и избежать проблем с кодировками и специальными символами XML в обычных строковых полях.Подводя итог, можно сказать, что основная ошибка кроется в «автоматизме» платформы. Для корректного восстановления сложного объекта XDTO программист должен явно управлять именами элементов и типами данных на каждом этапе обмена.