Как исправить ошибку при чтении XML для реквизитов составного типа в 1С?

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

При реализации механизмов обмена данными через XML программисты часто сталкиваются с досадной ошибкой: «Значения данного типа не могут быть представлены в XML». Ситуация осложняется тем, что ошибка возникает именно в момент вызова стандартной функции ПрочитатьXML(), когда платформа пытается автоматически преобразовать содержимое узла в объект базы данных. Особенно остро эта проблема проявляется, если реквизит объекта (например, «Основание» или «Владелец») имеет составной тип данных.

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

Выясним причину: почему 1С «спотыкается» на составных типах?

Давайте проанализируем ситуацию. Когда мы имеем дело с простым типом (например, ссылка на конкретный справочник «Контрагенты»), платформа заранее знает, к какой таблице базы данных относится GUID, указанный в XML. Однако в случае с составным типом ситуация меняется. Один и тот же уникальный идентификатор (GUID) теоретически может существовать в разных таблицах (справочниках, документах).

Для корректной десериализации (чтения) объекта из XML платформе недостаточно просто получить строковое представление ссылки. Ей необходимо точно знать, к какому именно типу относится это значение. Если в XML-файле передан просто идентификатор без указания типа, ПрочитатьXML() не может принять решение о преобразовании и выдает исключение.

Решение 1: Использование атрибута xsi:type в XML

Рассмотрим самый правильный способ исправления структуры самого XML-файла. Чтобы платформа могла прочитать значение составного типа, узел должен содержать специальный атрибут xsi:type, указывающий на конкретный тип данных из пространства имен конфигурации.

Проанализируем пример «неправильного» XML:

<Основание>7f1c378c-cc83-11ed-bbc4-b80d54af843b</Основание>

А теперь посмотрим, как должен выглядеть «правильный» узел, чтобы 1С прочитала его без ошибок:


<Основание xmlns:xs="http://www.w3.org/2001/XMLSchema" 
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
           xsi:type="cfg:DocumentRef.РеализацияТоваровУслуг">7f1c378c-cc83-11ed-bbc4-b80d54af843b</Основание>

В данном случае префикс cfg должен соответствовать пространству имен вашей конфигурации (обычно это http://v8.1c.ru/8.1/data/enterprise/current-config). Таким образом, мы явно говорим платформе: «Возьми этот GUID и ищи его в таблице документов Реализация товаров и услуг».

Решение 2: Правильная обработка пустых значений

Часто ошибка возникает при попытке передать «пустую ссылку» в поле составного типа. Нужно запомнить важное правило: для составного типа в 1С отсутствие значения — это Неопределено, а не пустая ссылка конкретного типа.

Разберем, в чем разница при сериализации:

  1. Пустая ссылка: 00000000-0000-0000-0000-000000000000. Если вы записываете это значение, вы ОБЯЗАНЫ указать тип (например, xsi:type="cfg:CatalogRef.Склады"). Но это избыточно, если данных действительно нет.
  2. Неопределено (Undefined): В XML это должно быть представлено либо отсутствием тега, либо специальным атрибутом xsi:nil="true".

Рассмотрим пример кода, который правильно подготавливает данные перед записью в XML, чтобы избежать проблем при последующем чтении:


Если Не ЗначениеЗаполнено(Объект.Основание) Тогда
    // Если реквизит составного типа, лучше установить Неопределено
    Объект.Основание = Неопределено; 
КонецЕсли;

Если в XML записать Неопределено, платформа при чтении просто пропустит этот реквизит или присвоит ему пустое значение без лишних проверок типов.

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

Если вы столкнулись с тем, что стандартные функции ПрочитатьXML и ЗаписатьXML не справляются, рекомендуется перейти на использование объекта СериализаторXDTO. Этот механизм лежит в основе всей работы платформы с XML и предоставляет гораздо больше контроля.

Рассмотрим пример чтения данных через СериализаторXDTO:


ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ПутьКФайлу);

// Читаем сообщение обмена
ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
ЧтениеСообщения.НачатьЧтение(ЧтениеXML);

Пока ВозможностьЧтенияXML(ЧтениеXML) Цикл
    // Вместо ПрочитатьXML(ЧтениеXML) используем Сериализатор
    Данные = СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
    // ... обработка данных
КонецЦикла;

Метод СериализаторXDTO.ПрочитатьXML() работает более гибко и часто позволяет обойти строгие ограничения, которые накладываются при чтении через ПланыОбмена.

Решение 4: Ручной разбор «проблемных» узлов

Бывают ситуации, когда вы не можете изменить формат входящего XML (например, файл приходит из сторонней системы, которая не умеет ставить xsi:type). В этом случае нам придется отказаться от автоматического чтения всего объекта целиком и реализовать «ручной» обход узлов.

Проанализируем алгоритм такого решения:

  1. Используем цикл ЧтениеXML.Прочитать() для перебора всех элементов.
  2. Когда курсор попадает на узел с именем «Основание», мы читаем его содержимое как обычную строку (GUID).
  3. Вручную создаем ссылку нужного типа, если мы заранее знаем, какие типы могут там быть.

Посмотрим на пример кода:


Пока ЧтениеXML.Прочитать() Цикл
    Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента И ЧтениеXML.Имя = "Основание" Тогда
        СтрокаGUID = ЧтениеXML.ПрочитатьСтроку();
        Если ЗначениеЗаполнено(СтрокаGUID) Тогда
            // Если мы знаем, что это может быть только справочник Контрагенты
            Ссылка = Справочники.Контрагенты.ПолучитьСсылку(Новый УникальныйИдентификатор(СтрокаGUID));
            // Присваиваем объекту
            НовыйОбъект.Основание = Ссылка;
        КонецЕсли;
    КонецЕсли;
КонецЦикла;

Важные замечания по пространствам имен (Namespaces)

Нужно учитывать, что ошибка «Значения данного типа не могут быть представлены в XML» часто возникает при обмене между разными конфигурациями. Если база-источник говорит, что это тип DocumentRef.ЗаказПокупателя, а в базе-приемнике такого документа нет или он называется DocumentRef.ЗаказКлиента, чтение упадет.

В таких случаях «платформенное» чтение в объекты из пространства имен v8currentconfig работать не будет. Рекомендуем создавать свои XDTO-пакеты, описывающие универсальную структуру данных, которая не зависит от метаданных конкретной базы. Это позволит гибко сопоставлять типы данных при чтении. При необходимости можно использовать обработку для проверки валидности XML по схеме XSD или пакету XDTO.

Подведем итог: для успешного чтения составных типов в XML важно либо обеспечить наличие атрибута xsi:type, либо использовать Неопределено для пустых значений, либо переходить на низкоуровневое чтение через ЧтениеXML и СериализаторXDTO. Это обеспечит стабильность ваших интеграций и избавит от ошибок в процессе обмена данными.

← На главную