Как передать значение в XDTO-объект типа anyType с указанием xsi:type в 1С

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

При интеграции 1С с внешними Web-сервисами программисты часто сталкиваются с ситуацией, когда один из аргументов метода имеет универсальный тип anyType. Согласно спецификации XML, такой тип может содержать практически любые данные. Однако на практике сторонние сервисы часто требуют строгого соблюдения структуры: элемент должен не только содержать значение, но и иметь явный атрибут xsi:type, указывающий на тип данных (например, xsd:int или xsd:string).

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

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

Рассмотрим ситуацию, когда сервис ожидает XML следующего вида:

<arg2 xsi:type="xsd:int">0</arg2>

Попытка создать такой объект через ФабрикаXDTO.Создать() и последующее добавление текста в Последовательность() часто приводит к ошибке «Недостаточно фактических параметров». Это происходит из-за особенностей реализации метода Добавить() в объекте ПоследовательностьXDTO в старых релизах платформы (до 8.3.14). Система ожидает второй параметр, даже если вы добавляете простой текст.

Кроме того, если тип anyType в используемой схеме не помечен свойством Смешанный (Mixed) = Истина, работа с последовательностью и добавление текста будут заблокированы на уровне ядра XDTO.

Решение 1: Использование последовательности с обходом ошибки платформы

Если ваша платформа ниже версии 8.3.14, или если вы хотите использовать наиболее «правильный» с точки зрения объектной модели путь, воспользуйтесь методом работы с последовательностью. Чтобы избежать ошибки количества параметров, необходимо передать Неопределено в качестве второго аргумента.

Разберем этот метод по шагам:

  1. Создаем объект типа anyType через фабрику вашего WS-сервиса.
  2. Добавляем необходимые атрибуты (в данном случае xsi:type).
  3. Получаем последовательность объекта.
  4. Добавляем текстовое значение, передавая пустой второй параметр.

Пример кода:


// Создаем тип anyType из стандартного пространства имен XML Schema
ТипAnyType = ФабрикаXDTO.Тип("http://www.w3.org/2001/XMLSchema", "anyType");
ОбъектXDTO = ФабрикаXDTO.Создать(ТипAnyType);

// Добавляем атрибут xsi:type вручную, если это необходимо
// Хотя зачастую 1С сама управляет этим при правильной типизации
ЗначениеТипа = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип("http://www.w3.org/2001/XMLSchema", "string"), "xsd:integer");
ОбъектXDTO.Добавить(ФормаXML.Атрибут, "http://www.w3.org/2001/XMLSchema-instance", "type", ЗначениеТипа);

// Работаем с последовательностью для добавления текстового содержимого (#text)
ТекПоследовательность = ОбъектXDTO.Последовательность();
Если ТекПоследовательность <> Неопределено Тогда
    // Важно: передаем Неопределено вторым параметром для совместимости
    ТекПоследовательность.Добавить("777720109", Неопределено);
КонецЕсли;

Решение 2: Формирование через XML-поток (Memory Stream)

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

Посмотрим на реализацию этого алгоритма:


// 1. Подготавливаем поток в памяти для записи XML
Поток = Новый ПотокВПамяти();
Запись = Новый ЗаписьXML;
Запись.ОткрытьПоток(Поток);

// 2. Формируем структуру вручную
Запись.ЗаписатьОбъявлениеXML();
Запись.ЗаписатьНачалоЭлемента("anyType");
// Объявляем необходимые пространства имен
Запись.ЗаписатьАтрибут("xmlns", "http://www.w3.org/2001/XMLSchema");
Запись.ЗаписатьАтрибут("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
// Указываем тип через атрибут
Запись.ЗаписатьАтрибут("xsi:type", "xsd:int");
// Записываем само значение (текстовый узел)
Запись.ЗаписатьТекст("777720109");
Запись.ЗаписатьКонецЭлемента();
Запись.Закрыть();

// 3. Читаем сформированный XML обратно в объект XDTO
Поток.Перейти(0, ПозицияВПотоке.Начало);
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьПоток(Поток);

// Используем ФабрикаXDTO.ПрочитатьXML для получения готового объекта
ОбъектРезультат = ФабрикаXDTO.ПрочитатьXML(Чтение);

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

// Теперь ОбъектРезультат можно присвоить свойству другого XDTO-объекта

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

Решение 3: Использование XDTOЗначение вместо XDTOОбъект

Проанализируем ситуацию: если свойство имеет тип anyType, а нам нужно передать простое число, мы можем создать не XDTOОбъект, а XDTOЗначение. Платформа 1С при сериализации объектов XDTOЗначение в поля типа anyType часто автоматически добавляет атрибут xsi:type.

Пример использования XDTOЗначение:


// Получаем тип xsd:int
ТипЧисло = ФабрикаXDTO.Тип("http://www.w3.org/2001/XMLSchema", "int");
// Создаем именно значение, а не объект
ЗначениеXDTO = ФабрикаXDTO.Создать(ТипЧисло, 777720109);

// Присваиваем это значение свойству родительского объекта
// РодительскийОбъект.СвойствоТипаAnyType = ЗначениеXDTO;

В этом случае 1С увидит, что в поле «любого типа» передано конкретное типизированное значение, и при выгрузке в XML добавит xsi:type="xsd:int" самостоятельно. Это наиболее лаконичный способ, если он поддерживается конкретной реализацией вашего Web-сервиса.

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

При ручном добавлении атрибутов типа xsi:type крайне важно следить за префиксами пространств имен. В XML-документе префикс xsi должен быть привязан к URI http://www.w3.org/2001/XMLSchema-instance, а префикс xsd (или другой, используемый в значении типа) — к http://www.w3.org/2001/XMLSchema.

Если вы используете метод ОбъектXDTO.Добавить(), убедитесь, что вы передаете правильный URI пространства имен атрибута, иначе сервис может не распознать тип данных и вернуть ошибку валидации.

Подведем итог: для решения проблемы с anyType в старых версиях 1С используйте добавление в последовательность с параметром Неопределено. Для максимально гибкого контроля структуры используйте метод с промежуточным ПотокВПамяти и ЗаписьXML. А для простых типов данных сначала попробуйте создание XDTOЗначение с явным указанием типа из пространства имен XMLSchema.

← На главную