Как сохранить объект XDTO в реквизит документа и восстановить его с сохранением типа

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

При разработке сложных интеграций или сохранении промежуточных данных в 1С:Предприятии часто возникает необходимость упаковать объект XDTO в текстовую строку (XML) для хранения в реквизите документа или справочника, а затем восстановить его обратно в виде полноценного объекта. Однако разработчики часто сталкиваются с проблемой: при чтении XML объект теряет свой исходный тип и превращается в универсальный anyType, что делает невозможным его дальнейшее использование в рамках пакета XDTO. Рассмотрим подробно, почему это происходит и как правильно реализовать процесс сериализации и десериализации.

Анализ проблемы: почему тип объекта превращается в anyType

Разберем ситуацию на примере кода, представленного в обсуждении. При записи объекта используется метод ЗаписатьXML, где в качестве параметров передаются сама запись, объект данных и пространство имен. Однако один из ключевых параметров — ЛокальноеИмя — часто оставляется пустым. Проанализируем, к чему это приводит.

Когда мы вызываем ФабрикаXDTO.ЗаписатьXML(ЗаписьXML, ДанныеXDTO) без указания локального имени, платформа пытается самостоятельно определить имя тега. Если ДанныеXDTO созданы на основе ТипаОбъектаXDTO (ComplexType), а не на основе конкретного Элемента схемы, система не «знает», каким тегом обернуть данные. В результате в XML-файле появляется корень anyType.

Ситуация усугубляется использованием параметра НазначениеТипаXML.Явное. В этом случае 1С принудительно записывает в XML атрибут xsi:type="xs:anyType". При последующем чтении, даже если вы попытаетесь указать фабрике ожидаемый тип, атрибут xsi:type внутри самого XML будет иметь приоритет, и вы получите объект anyType, который не подходит для вставки в строго типизированные коллекции.

Решение №1: Правильное использование Фабрики XDTO при записи

Для того чтобы объект сохранил свою структуру и тип, необходимо явно указывать имя корневого элемента при записи. Давайте пересмотрим подход к сохранению объекта.

Рассмотрим пошагово правильный алгоритм записи:


// 1. Подготовка записи XML
ЗаписьXML = Новый ЗаписьXML();
ЗаписьXML.УстановитьСтроку();

// 2. Определение параметров записи
// Указываем конкретное имя тега, которое соответствует вашей схеме (например, "Документ")
ЛокальноеИмя = "Документ";
ПространствоИмен = "urn:1C.ru:commerceml_3";

// Важно: используем НазначениеТипаXML.Неявное, чтобы избежать жесткой привязки к anyType в атрибутах
МояФабрикаXDTO.ЗаписатьXML(ЗаписьXML, ДанныеXDTO, ЛокальноеИмя, ПространствоИмен, , НазначениеТипаXML.Неявное);

ЗначениеXML = ЗаписьXML.Закрыть();

В данном примере мы явно задали имя узла Документ. Теперь при чтении этого XML платформа сможет сопоставить структуру с метаданными из пакета XDTO.

Решение №2: Восстановление объекта с явным указанием типа

При чтении XML-строки из реквизита документа недостаточно просто вызвать метод ПрочитатьXML. Чтобы гарантированно получить объект нужного типа, его необходимо передать вторым параметром в метод фабрики. Выясним, как это сделать правильно:


// 1. Подготовка чтения
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(СтрокаИзРеквизита);

// 2. Получение типа из фабрики
ТипДокументXDTO = МояФабрикаXDTO.Тип("urn:1C.ru:commerceml_3", "Документ");

// 3. Чтение с типизацией
// Передача типа вторым параметром заставляет фабрику интерпретировать XML именно как этот тип
Попытка
    XDTOДокумент = МояФабрикаXDTO.ПрочитатьXML(ЧтениеXML, ТипДокументXDTO);
Исключение
    Сообщить("Ошибка чтения XDTO: " + ОписаниеОшибки());
КонецПопытки;

Именно связка Явное локальное имя при записи + Передача типа при чтении позволяет избежать ошибки Несоответствие типов XDTO.

Решение №3: Использование Сериализатора XDTO

Если ваша задача — сохранить объект XDTO внутри одной и той же информационной базы для внутреннего использования (например, кэширование или отложенная обработка), более надежным и простым инструментом может выступить СериализаторXDTO. В отличие от базовой фабрики, сериализатор умеет работать с объектами 1С более нативно.

Проанализируем пример использования сериализатора:


// Запись
ЗаписьXML = Новый ЗаписьXML();
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ДанныеXDTO);
СтрокаXML = ЗаписьXML.Закрыть();

// Чтение
ЧтениеXML = Новый ЧтениеXML();
ЧтениеXML.УстановитьСтроку(СтрокаXML);
ВосстановленныйОбъект = СериализаторXDTO.ПрочитатьXML(ЧтениеXML);

Важное ограничение: этот метод идеально работает, если типы определены в конфигурации или если вы используете стандартную фабрику XDTO. Если же вы работаете с внешней схемой через свою созданную фабрику, лучше придерживаться методов, описанных в Решении №1 и №2.

Дополнительные рекомендации по работе с XML и XDTO

Рассмотрим несколько нюансов, которые могут повлиять на результат:

  1. Проверка пространства имен: Убедитесь, что при записи и чтении используется одно и то же пространство имен (URI). Даже небольшая опечатка приведет к тому, что фабрика не найдет описание типа и создаст anyType.
  2. Свойство elementFormDefault: В файлах описания схем (XSD) есть настройка elementFormDefault. Если она установлена в unqualified, то дочерние элементы XML не будут иметь префикса пространства имен. В этом случае при чтении обязательно нужно указывать тип, иначе фабрика не поймет, к какому описанию относятся эти «безымянные» поля.
  3. Хранение в БД: Для хранения XML-данных большого объема лучше использовать реквизит с типом ХранилищеЗначения. Это позволит не только сжимать данные, но и избежать проблем с кодировками и специальными символами XML в обычных строковых полях.

Подводя итог, можно сказать, что основная ошибка кроется в «автоматизме» платформы. Для корректного восстановления сложного объекта XDTO программист должен явно управлять именами элементов и типами данных на каждом этапе обмена.

← На главную