Как исправить ошибку преобразования данных XDTO «Проверка дополнительного свойства: форма: Текст» при чтении XML?

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

При десериализации входящего XML-документа с помощью механизма XDTO разработчики нередко сталкиваются с ошибкой валидации структуры. Платформа 1С аварийно завершает чтение со следующим диагностическим сообщением:

Ошибка преобразования данных XDTO: Чтение объекта типа: {...}sales - Проверка дополнительного свойства: форма: Текст, имя:

Разберем по шагам, почему возникает эта ошибка, как настроить XDTO-пакет для корректного чтения документа и какие альтернативные механизмы платформы лучше использовать, если структура XML во внешней системе регулярно меняется.

Причины возникновения ошибки

Проанализируем ситуацию: в сообщении об ошибке фигурирует родительский тип sales, а не дочерний элемент sale. Выясним главные причины такого поведения парсера 1С:

  1. Наличие неименованных текстовых узлов (пробелы и переводы строк): Если XML-файл отформатирован с отступами, между открывающим тегом <sales> и вложенным <sale> содержатся символы перевода строки и пробелы. Парсер 1С воспринимает их как текстовый узел (форма: Текст с пустым именем). Если у типа sales в XDTO-пакете отключен флаг Смешанный, фабрика ожидает исключительно строгие дочерние теги и падает при встрече любого форматирующего текста.
  2. Ограничения флага «Открытый» (Open Content): Установка свойства Открытый = Истина у типа XDTO позволяет элементу принимать дополнительные свойства, но только если платформа может однозначно определить их типы (например, когда во входящем XML явно указан атрибут xsi:type="..." или свойства заранее описаны в глобальной фабрике). Если сторонняя система передает произвольные теги без указания схемы, фабрика XDTO не сможет их сопоставить.

Способ 1. Корректировка настроек типов в пакете XDTO

Если требуется продолжить работу именно через ФабрикаXDTO, скорректируем настройки типов в пакете XDTO:

  1. Настройка родительского типа (sales): Установим для типа sales свойства Смешанный = Истина и Последовательный = Истина. Это укажет фабрике, что внутри контейнера допустимы текстовые разделители (пробелы, переносы строк), и парсинг не прервется.
  2. Использование универсального типа anyType: Чтобы элемент sale мог принимать произвольные дочерние элементы без строгого описания всех полей в схеме, укажем для свойства sale тип anyType из пространства имен http://www.w3.org/2001/XMLSchema.
  3. Настройка формы свойств: Если в XML внутри тега передаются и атрибуты, и текстовое значение (например, <sale id="1">Значение</sale>), в типе XDTO свойству для значения необходимо задать параметр Форма = Текст.

Способ 2. Потоковое чтение через объект ЧтениеXML

Когда сторонняя система периодически добавляет новые теги, а нам требуется извлечь только определенный набор реквизитов, наиболее надежным решением является потоковый парсер ЧтениеXML. Он полностью игнорирует нерегламентированные теги и не требует создания жестких схем.

Посмотрим на пример обработки документа в цикле:


Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл("C:\exchange\sales.xml");

ТекущаяПродажа = Неопределено;

Пока Чтение.Прочитать() Цикл
    // Фиксируем начало элемента sale
    Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента И Чтение.Имя = "sale" Тогда
        ТекущаяПродажа = Новый Структура("Сумма, Номер, Контрагент");
    КонецЕсли;
    
    // Считываем только нужные свойства внутри элемента
    Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента И ТекущаяПродажа <> Неопределено Тогда
        ИмяРеквизита = Чтение.Имя;
        
        Если ТекущаяПродажа.Свойство(ИмяРеквизита) Тогда
            Чтение.Прочитать(); // Переходим к значению внутри тега
            Если Чтение.ТипУзла = ТипУзлаXML.Текст Тогда
                ТекущаяПродажа[ИмяРеквизита] = Чтение.Значение;
            КонецЕсли;
        КонецЕсли;
    КонецЕсли;
    
    // Фиксируем конец элемента sale и сохраняем результат
    Если Чтение.ТипУзла = ТипУзлаXML.КонецЭлемента И Чтение.Имя = "sale" Тогда
        Если ТекущаяПродажа <> Неопределено Тогда
            // Обрабатываем полученную структуру данных
            ЗаписатьПродажуВБазу(ТекущаяПродажа);
            ТекущаяПродажа = Неопределено;
        КонецЕсли;
    КонецЕсли;
КонецЦикла;

Чтение.Закрыть();

Способ 3. Использование объектной модели DOM

Если размер XML-файла невелик (умещается в оперативной памяти), удобно разобрать документ с помощью ПостроительDOM и ДокументDOM. Этот способ позволяет выбирать только целевые узлы по имени тега, полностью игнорируя лишние поля.

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


Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл("C:\exchange\sales.xml");

Построитель = Новый ПостроительDOM;
Документ = Построитель.Прочитать(Чтение);
Чтение.Закрыть();

// Получаем коллекцию всех узлов <sale>
СписокПродаж = Документ.ПолучитьЭлементыПоИмени("sale");

Для Каждого УзелПродажи Из СписокПродаж Цикл
    Сумма = "";
    Номер = "";
    
    // Ищем только требуемые дочерние узлы
    УзлыСуммы = УзелПродажи.ПолучитьЭлементыПоИмени("sum");
    Если УзлыСуммы.Количество() > 0 Тогда
        Сумма = УзлыСуммы.Получить(0).ТекстовоеСодержимое;
    КонецЕсли;
    
    УзлыНомера = УзелПродажи.ПолучитьЭлементыПоИмени("docNumber");
    Если УзлыНомера.Количество() > 0 Тогда
        Номер = УзлыНомера.Получить(0).ТекстовоеСодержимое;
    КонецЕсли;
    
    // Новые и сторонние узлы внутри <sale> будут автоматически проигнорированы
    ОбработатьЗапись(Номер, Сумма);
КонецЦикла;

Способ 4. Предварительная XSLT-трансформация

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

← На главную