Почему объект XDTO не проходит проверку после заполнения свойства __content и как это исправить?

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

При интеграции систем через XML-документы разработчики на платформе 1С часто используют технологии XDTO (XML Data Transfer Objects). Этот механизм позволяет прозрачно работать со сложными структурами данных, валидировать их по схемам XSD и сериализовать в XML-формат. Однако при работе со специфическими типами данных возникает неприятная проблема: заполненное свойство __content упорно не проходит проверку встроенным методом Проверить(), генерируя ошибку о том, что обязательное свойство отсутствует. При этом в табло отладчика свойство выглядит абсолютно корректно заполненным.

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

Суть свойства __content и особенности схем XSD

Для начала давайте разберем, откуда вообще берется свойство с двойным подчеркиванием __content. В XML-схемах (XSD) элементы могут определяться по-разному. Довольно часто встречается структура, когда элемент должен содержать текстовое значение (простой тип), но в то же время иметь несколько атрибутов. В терминах XSD такая структура описывается как сложный тип с простым содержимым (complexType с расширением simpleContent).

Рассмотрим пример такого XML-элемента:

<Account bic="044525225" name="ПАО Сбербанк">40702810938000001234</Account>

Здесь bic и name выступают в качестве атрибутов XML-тега, а банковский счет 40702810938000001234 — это непосредственное текстовое тело элемента. Платформа 1С при импорте такой схемы XSD не может представить текстовое значение как обычное свойство объекта XDTO, поскольку у объекта уже есть свойства-атрибуты. Чтобы решить эту коллизию, платформа автоматически генерирует системное скрытое свойство с зарезервированным именем __content. Именно в него записывается текстовая составляющая XML-элемента.

При заполнении такого объекта разработчики обычно пишут следующий код:


НовыйОбъект = ФабрикаXDTO.Создать(ТипОбъекта);
НовыйОбъект.bic = "044525225";
НовыйОбъект.name = "ПАО Сбербанк";
НовыйОбъект.__content = "40702810938000001234";

Казалось бы, все сделано правильно. Но при вызове метода НовыйОбъект.Проверить() платформа выбрасывает исключение: "Проверка свойства '__content': отсутствует обязательное свойство". Выясним, почему так происходит.

Анализ причин проблемы: конфликт пространств имен

Главная и самая неочевидная причина кроется в архитектуре платформы 1С:Предприятие при работе с фабриками XDTO. Давайте проанализируем поведение платформы по шагам:

  1. В конфигурации 1С могут быть объявлены собственные XDTO-пакеты (в дереве метаданных). Каждый такой пакет привязан к конкретному пространству имен (URI), например, http://www.cbr.ru/projects/formats.
  2. Для интеграции с внешним сервисом разработчик динамически загружает файл схемы XSD (например, из макета или внешнего файла) и создает на его основе собственную фабрику XDTO с помощью конструктора СоздатьФабрикуXDTO(ПутьКФайлуСхемы).
  3. Внешняя схема XSD содержит то же самое пространство имен (targetNamespace), что и один из встроенных в конфигурацию XDTO-пакетов.
  4. Критическое поведение платформы: Если пространство имен динамически загружаемой схемы совпадает с пространством имен пакета, уже зарегистрированного в метаданных конфигурации, платформа 1С полностью игнорирует переданный внешний файл XSD! Вместо него для создания типов данных используется встроенный пакет из метаданных.

Если встроенный в конфигурацию XDTO-пакет устарел, был изменен или изначально не содержал корректного описания типа simpleContent для нужного нам свойства, созданный объект XDTO фактически инициализируется по старой схеме. В этой старой схеме свойство __content может не существовать в качестве текстового заполнения или иметь другой тип данных. В результате, несмотря на то что отладчик позволяет нам записать значение в __content динамически, внутренний валидатор платформы считает структуру объекта некорректной и бракует его при проверке.

Решение 1: Динамическая подмена пространства имен (Рекомендуемый метод)

Самый надежный способ обойти данное ограничение платформы — сделать пространство имен загружаемой схемы уникальным в рамках текущего сеанса работы. Поскольку уникальность схем в фабрике XDTO жестко привязана к строке URI пространства имен, мы можем программно изменить его перед созданием фабрики, а затем вернуть исходное значение на этапе формирования финального XML-документа.

Давайте подробно разберем этот алгоритм по шагам:

  1. Прочитаем файл схемы XSD как обычный текст.
  2. С помощью функции СтрЗаменить() заменим оригинальное пространство имен на временное (например, добавив к нему суффикс /temp). Замену нужно произвести как в объявлении targetNamespace, так и во всех импортах и префиксах внутри схемы.
  3. Запишем измененную схему во временный файл и создадим фабрику XDTO на его основе.
  4. Создадим и заполним наш объект XDTO. Теперь платформа гарантированно использует нашу новую динамическую схему, и проверка Проверить() пройдет успешно.
  5. Сериализуем объект в XML-строку.
  6. В полученной XML-строке выполним обратную замену временного пространства имен на оригинальное, чтобы принимающая сторона успешно распознала наш файл.

Посмотрим на практический пример реализации этого метода в коде 1С:


// Шаг 1. Получаем текст исходной схемы XSD (например, из макета)
ТекстСхемы = ПолучитьМакет("ИмпортируемаяСхемаXSD").ПолучитьТекст();

ОригинальноеПространство = "http://www.cbr.ru/projects/formats";
ВременноеПространство   = "http://www.cbr.ru/projects/formats/temp";

// Шаг 2. Подменяем пространство имен в тексте схемы
МодифицированныйТекстСхемы = СтрЗаменить(ТекстСхемы, ОригинальноеПространство, ВременноеПространство);

// Шаг 3. Записываем временную схему на диск
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xsd");
ТекстовыйДокумент = Новый ТекстовыйДокумент;
ТекстовыйДокумент.УстановитьТекст(МодифицированныйТекстСхемы);
ТекстовыйДокумент.Записать(ИмяВременногоФайла, КодировкаТекста.UTF8);

// Шаг 4. Создаем фабрику XDTO на основе модифицированной схемы
МассивФайлов = Новый Массив;
МассивФайлов.Добавить(ИмяВременногоФайла);
ВременнаяФабрика = СоздатьФабрикуXDTO(МассивФайлов);

// Удаляем временный файл с диска
Попытка
    УдалитьФайлы(ИмяВременногоФайла);
Исключение
    // Обработка возможных ошибок блокировки файла
КонецПопытки;

// Шаг 5. Работаем с объектом XDTO через новую фабрику
ТипАккаунт = ВременнаяФабрика.Тип(ВременноеПространство, "AccNumType");
ОбъектAccount = ВременнаяФабрика.Создать(ТипАккаунт);

ОбъектAccount.bic = "044525225";
ОбъектAccount.name = "ПАО Сбербанк";
ОбъектAccount.__content = "40702810938000001234";

// Проверяем объект - теперь ошибки не возникнет!
Если Не ОбъектAccount.Проверить() Тогда
    ВызватьИсключение "Ошибка валидации объекта XDTO!";
КонецЕсли;

// Шаг 6. Сериализуем объект в XML-строку
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
ВременнаяФабрика.ЗаписатьXML(ЗаписьXML, ОбъектAccount, "Account", ВременноеПространство);
ВременнаяXMLСтрока = ЗаписьXML.Закрыть();

// Шаг 7. Возвращаем оригинальное пространство имен в XML-документ
ФинальныйXML = СтрЗаменить(ВременнаяXMLСтрока, ВременноеПространство, ОригинальноеПространство);

Этот способ является максимально надежным, так как он полностью изолирует динамически загружаемую схему от метаданных конфигурации 1С и гарантирует предсказуемое поведение платформы при выполнении валидации.

Решение 2: Использование последовательностей XDTO для смешанного содержимого (Mixed Content)

В некоторых случаях структура элемента описывается в XSD не как simpleContent, а как тип со смешанным содержимым (mixed="true"). При такой структуре элемент может содержать одновременно и дочерние XML-теги, и произвольный текст между ними.

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

Проанализируем ситуацию и рассмотрим пример кода, который позволяет обойти проблему валидации через добавление текста в последовательность:


ТипОбъекта = ФабрикаXDTO.Тип(ПространствоИмен, "ComplexMixedType");
НовыйОбъект = ФабрикаXDTO.Создать(ТипОбъекта);

// Заполняем обычные атрибуты или дочерние свойства
НовыйОбъект.SomeAttribute = "ЗначениеАтрибута";

// Работаем с последовательностью для заполнения текстового содержимого
Если НовыйОбъект.Последовательность() <> Неопределено Тогда
    // Добавляем текст непосредственно в последовательность XDTO
    НовыйОбъект.Последовательность().ДобавитьТекст("Текстовое значение элемента");
КонецЕсли;

// Выполняем проверку заполнения
Если НовыйОбъект.Проверить() Тогда
    // Объект успешно прошел валидацию
КонецЕсли;

Этот подход незаменим, когда схема XSD накладывает жесткие требования к порядку следования текстовых блоков и дочерних узлов XML-документа.

Решение 3: Корректировка XDTO-пакетов в конфигурации или расширении

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

  1. Найдите в ветке метаданных "Общие -> XDTO-пакеты" тот пакет, пространство имен которого совпадает с вашей динамической схемой.
  2. Обновите этот пакет актуальной схемой XSD. Для этого нажмите правой кнопкой мыши на XDTO-пакете и выберите пункт "Импортировать схему XML".
  3. Убедитесь, что после обновления структуры типа в пакете конфигурации у нужного объекта появилось свойство с типом, поддерживающим текстовое содержимое.
  4. Если основная конфигурация находится на поддержке поставщика и не подлежит изменению, добавьте аналогичный XDTO-пакет в расширение конфигурации и выполните его обновление там (доступно в версиях платформы 1С 8.3.13 и выше).

После приведения встроенных метаданных в соответствие с актуальной схемой необходимость динамической замены пространств имен отпадет сама собой, и вы сможете использовать стандартные методы создания объектов через общую системную фабрику XDTO.

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

← На главную