Как динамически добавлять элементы и атрибуты в XDTO и находить данные без использования циклов в 1С

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

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

В этой статье мы подробно разберем, как решить эти проблемы, проанализируем частые ошибки и рассмотрим эффективные методики работы с динамическими объектами XDTO.

Проблема №1: Неверная вложенность при динамическом добавлении объектов (структура Группа -> Правило)

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

л_Правило = л_ПравилоГрп.Добавить("Правило", XDTOНовый());

В результате вместо вложенной структуры вида <Группа><Правило>...</Правило></Группа> разработчик получает «плоскую» структуру, где реквизиты правила записываются непосредственно внутрь группы, минуя сам тег правила.

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

Добавить(<Форма>, <URIПространстваИмен>, <ЛокальноеИмя>, <ЭлементДанных>)

Давайте разберем по шагам, как правильно создать вложенную структуру «Группа -> Правило»:

  1. Сначала определим вспомогательную функцию для быстрого создания пустых объектов типа anyType (поскольку схемы у нас нет, мы используем базовый тип XML-схемы):

Функция XDTOНовый(Знач п_URI = Неопределено, Знач п_ИмяТипа = Неопределено) Экспорт
    Если п_URI = Неопределено Тогда
        п_URI = "http://www.w3.org/2001/XMLSchema";
    КонецЕсли;
    Если п_ИмяТипа = Неопределено Тогда
        п_ИмяТипа = "anyType";
    КонецЕсли;
    л_Тип = ФабрикаXDTO.Тип(п_URI, п_ИмяТипа);
    Возврат ФабрикаXDTO.Создать(л_Тип);
КонецФункции
  1. Теперь напишем корректный код создания вложенной структуры. Сначала мы создаем объект правила, заполняем его реквизитами, а затем добавляем его в объект группы как подчиненный элемент:

// 1. Создаем объекты Группы и Правила
л_Группа = XDTOНовый();
л_Правило = XDTOНовый();

// Для заполнения строковых значений получим тип "string"
ТипСтрока = ФабрикаXDTO.Тип("http://www.w3.org/2001/XMLSchema", "string");

// 2. Добавляем реквизиты внутрь Правила
л_Правило.Добавить(ФормаXML.Элемент, "http://www.w3.org/2001/XMLSchema", "Код", ФабрикаXDTO.Создать(ТипСтрока, "ПКО_Номенклатура"));
л_Правило.Добавить(ФормаXML.Элемент, "http://www.w3.org/2001/XMLSchema", "Источник", ФабрикаXDTO.Создать(ТипСтрока, "СправочникСсылка.Номенклатура"));

// 3. А теперь добавляем заполненное Правило в Группу!
л_Группа.Добавить(ФормаXML.Элемент, "http://www.w3.org/2001/XMLSchema", "Правило", л_Правило);

Благодаря использованию системного перечисления ФормаXML.Элемент платформа четко понимает, что внутри тега группы нужно создать новый XML-элемент (тег) с именем «Правило» и поместить туда структуру нашего объекта л_Правило.

Проблема №2: Быстрый поиск элемента в списке XDTO по реквизиту без циклов

Часто в процессе модификации XML-данных (например, правил обмена) нам нужно найти конкретный узел по его уникальному идентификатору или коду. Типичный подход начинающего разработчика — запустить цикл Для Каждого по всей коллекции СписокXDTO и сравнивать значение свойства в каждой итерации. Это существенно замедляет работу системы на больших объемах данных.

Мало кто знает, что встроенный механизм 1С поддерживает XPath-подобные выражения для быстрого поиска объектов в коллекциях XDTO. Метод Получить() объекта XDTO умеет выполнять фильтрацию списков «на лету».

Синтаксис поискового запроса выглядит следующим образом:

ИмяСвойстваСписка[ИмяРеквизитаДляПоиска='Значение']

Давайте проанализируем пример. Предположим, у нас есть объект л_ПКО (Правила Конвертации Объектов), внутри которого содержится список правил Правила. Нам нужно мгновенно найти правило, у которого свойство Код равно значению "СлужебныйКод":


// Поиск выполняется одной строкой без всяких циклов Для Каждого
НужноеПравило = л_ПКО.Получить("Правила[Код='СлужебныйКод']");

Если НужноеПравило <> Неопределено Тогда
    // Объект найден, можем производить с ним манипуляции
    Сообщить("Успешно нашли правило: " + НужноеПравило.Код);
Иначе
    Сообщить("Правило с таким кодом не обнаружено.");
КонецЕсли;

Платформа выполнит поиск на уровне оптимизированного внутреннего C++ кода, что работает в десятки раз быстрее, чем аналогичный обход коллекции средствами встроенного языка 1С.

Проблема №3: Как добавить атрибуты и текстовое значение в один и тот же динамический элемент anyType

Еще одна сложная задача при динамической генерации XML — создание элементов, которые одновременно содержат и атрибуты, и текстовое тело. Например, нам нужно получить следующий XML-код:

<Код ТипКода="ВПределахРодителя">12</Код>

Проблема заключается в том, что если мы просто запишем значение "12" в объект, мы не сможем добавить к нему атрибут, так как значение станет простым типом. Если мы сделаем его объектом anyType, то как записать текстовое значение "12" внутрь самого тега?

Решение кроется в использовании перечисления ФормаXML.Текст и ФормаXML.Атрибут при добавлении свойств в объект anyType. Давайте разберем этот процесс по шагам:


// 1. Создаем сам элемент "Код" как пустой anyType
ТипAnyType = ФабрикаXDTO.Тип("http://www.w3.org/2001/XMLSchema", "anyType");
ТипСтрока  = ФабрикаXDTO.Тип("http://www.w3.org/2001/XMLSchema", "string");
ОбъектКод  = ФабрикаXDTO.Создать(ТипAnyType);

// 2. Добавляем атрибут "ТипКода" со значением "ВПределахРодителя"
ЗначениеАтрибута = ФабрикаXDTO.Создать(ТипСтрока, "ВПределахРодителя");
ОбъектКод.Добавить(ФормаXML.Атрибут, "http://www.w3.org/2001/XMLSchema", "ТипКода", ЗначениеАтрибута);

// 3. Добавляем текстовое содержимое "12" непосредственно в тело тега.
// ВАЖНО: Для ФормаXML.Текст пространство имен и локальное имя передаются как пустые строки!
ЗначениеТекста = ФабрикаXDTO.Создать(ТипСтрока, "12");
ОбъектКод.Добавить(ФормаXML.Текст, "", "", ЗначениеТекста);

// 4. Помещаем готовый настроенный элемент "Код" в нашего родителя (например, в объект "Правило")
л_Правило.Добавить(ФормаXML.Элемент, "http://www.w3.org/2001/XMLSchema", "Код", ОбъектКод);

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

Альтернативный лайфхак: Использование текстового парсинга для сложных XML-структур

Если вам необходимо добавить огромный пласт вложенных XML-данных со множеством ветвлений и атрибутов, собирать его программно через сотни строк кода с вызовами ФабрикаXDTO.Создать() и Добавить() становится нерационально. Код становится нечитаемым и сложным в отладке.

В таких сценариях опытные разработчики используют эффективный обходной путь (лайфхак):

  1. Формируют нужный фрагмент XML в виде обычной текстовой строки (например, используя ЗаписьXML или простое сложение строк/шаблонов).
  2. Инициализируют объект ЧтениеXML этой строкой.
  3. Преобразуют строку в готовый объект XDTO через Фабрику.
  4. Вставляют полученный готовый узел в нужное место исходного дерева.

Давайте посмотрим, как это выглядит на практике:


// Формируем XML-код в виде строки
ТекстНовогоУзла = 
"<Правило xmlns=""http://www.w3.org/2001/XMLSchema"">
|   <Код ТипКода=""ВПределахРодителя"">12</Код>
|   <Источник>СправочникСсылка.Номенклатура</Источник>
|   <Приемник>СправочникСсылка.Номенклатура</Приемник>
|</Правило>";

// Читаем строку через ЧтениеXML
л_Чтение = Новый ЧтениеXML;
л_Чтение.УстановитьСтроку(ТекстНовогоУзла);

// Превращаем строку в полноценный объект XDTO типа anyType
л_НовыйОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(л_Чтение, ФабрикаXDTO.Тип("http://www.w3.org/2001/XMLSchema", "anyType"));
л_Чтение.Закрыть();

// Теперь просто добавляем этот готовый объект в нашу Группу
л_Группа.Добавить(ФормаXML.Элемент, "http://www.w3.org/2001/XMLSchema", "Правило", л_НовыйОбъектXDTO);

Этот подход экономит время разработчика, минимизирует количество ошибок при динамическом построении схемы и делает код интеграции лаконичным и легким для понимания.

← На главную