В процессе разработки часто возникает задача получить тип данных реквизита объекта метаданных в виде строки, которую мы привыкли видеть в конфигураторе, например, СправочникСсылка.Организации или ДокументСсылка.РеализацияТоваровУслуг. Стандартные методы, такие как .Имя или .ПолноеИмя() объекта метаданных реквизита, не дают желаемого результата. Метод .Имя вернет имя самого реквизита (например, "Организация"), а .ПолноеИмя() — полный путь к нему в дереве метаданных. Проблема усугубляется, если реквизит имеет составной тип.
Разберем по шагам, как решить эту задачу и получить корректное строковое представление типа для любого реквизита, включая реквизиты с составным типом данных.
Ключ к решению — это работа со свойством Тип объекта метаданных реквизита. Это свойство содержит описание типа, которое, в свою очередь, имеет метод Типы(), возвращающий коллекцию всех типов, входящих в состав типа данных реквизита. Даже если тип не составной, этот метод вернет коллекцию из одного элемента. Итерируя эту коллекцию, мы можем обработать каждый тип по отдельности.
Рассмотрим основной цикл, который обходит реквизиты документа и для каждого из них вызывает функцию получения строкового представления типа.
// Предполагается, что МетаданныеДокумента — это объект метаданных нужного документа,
// а ТекстовыйФайл — объект для записи результата.
Для Каждого Реквизит Из МетаданныеДокумента.Реквизиты Цикл
ИмяРеквизита = Реквизит.Имя;
// Вызываем нашу универсальную функцию для получения типа
ТипДанныхРеквизита = ПолучитьСтроковоеПредставлениеТипа(Реквизит);
СтрокаВыгрузки = "Реквизит;" + ИмяРеквизита + ";" + ТипДанныхРеквизита;
ТекстовыйФайл.ДобавитьСтроку(СтрокаВыгрузки);
КонецЦикла;
Теперь проанализируем, как должна быть устроена функция ПолучитьСтроковоеПредставлениеТипа(). Существует два основных способа ее реализации.
Этот способ является наиболее элегантным и производительным. Он основан на использовании системной функции XMLТип(), которая возвращает объект, содержащий XML-представление переданного ей типа. У этого объекта есть свойство ИмяТипа, которое для ссылочных типов возвращает строку в формате CatalogRef.ИмяСправочника или DocumentRef.ИмяДокумента. Нам остается лишь заменить англоязычные префиксы на русскоязычные.
Посмотрим на полную реализацию:
Сначала создадим функцию-обертку, которая будет обрабатывать составные типы и собирать итоговую строку.
Функция ПолучитьСтроковоеПредставлениеТипа(Реквизит, РазделительТипов = "; ")
ИтоговаяСтрокаТипов = "";
// Перебираем все типы, которые может иметь реквизит
Для Каждого Тип Из Реквизит.Тип.Типы() Цикл
// Добавляем разделитель, если это не первый тип в строке
Если НЕ ПустаяСтрока(ИтоговаяСтрокаТипов) Тогда
ИтоговаяСтрокаТипов = ИтоговаяСтрокаТипов + РазделительТипов;
КонецЕсли;
// Вызываем вспомогательную функцию для получения строки для одного типа
ИтоговаяСтрокаТипов = ИтоговаяСтрокаТипов + ПолучитьСтрокуОдногоТипа(Тип);
КонецЦикла;
Возврат ИтоговаяСтрокаТипов;
КонецФункции
Теперь реализуем вспомогательную функцию ПолучитьСтрокуОдногоТипа(), которая и будет основной рабочей лошадкой.
Функция ПолучитьСтрокуОдногоТипа(Тип)
// 1. Обрабатываем примитивные типы
Если Тип = Тип("Число") Тогда
Возврат "Число";
ИначеЕсли Тип = Тип("Булево") Тогда
Возврат "Булево";
ИначеЕсли Тип = Тип("Дата") Тогда
Возврат "Дата";
ИначеЕсли Тип = Тип("Строка") Тогда
Возврат "Строка";
ИначеЕсли Тип = Тип("ХранилищеЗначения") Тогда
Возврат "ХранилищеЗначения";
ИначеЕсли Тип = Тип("УникальныйИдентификатор") Тогда
Возврат "УникальныйИдентификатор";
// 2. Обрабатываем ссылочные и другие типы через XMLТип
Иначе
// Получаем XML-представление типа
Результат = XMLТип(Тип).ИмяТипа;
// Приводим к стандартному виду 1С
Результат = СтрЗаменить(Результат, "CatalogRef", "СправочникСсылка");
Результат = СтрЗаменить(Результат, "DocumentRef", "ДокументСсылка");
Результат = СтрЗаменить(Результат, "EnumRef", "ПеречислениеСсылка");
Результат = СтрЗаменить(Результат, "ChartOfAccountsRef", "ПланСчетовСсылка");
Результат = СтрЗаменить(Результат, "ChartOfCharacteristicTypesRef", "ПланВидовХарактеристикСсылка");
Результат = СтрЗаменить(Результат, "ChartOfCalculationTypesRef", "ПланВидовРасчетаСсылка");
Результат = СтрЗаменить(Результат, "ExchangePlanRef", "ПланОбменаСсылка");
Результат = СтрЗаменить(Результат, "BusinessProcessRef", "БизнесПроцессСсылка");
Результат = СтрЗаменить(Результат, "TaskRef", "ЗадачаСсылка");
Возврат Результат;
КонецЕсли;
КонецФункции
Преимущества данного подхода:
Этот метод также позволяет решить задачу, но является более громоздким. Его суть заключается в том, чтобы для каждого ссылочного типа создать пустой экземпляр объекта, получить его тип с помощью ТипЗнч(), а затем найти соответствующий объект в дереве метаданных функцией Метаданные.НайтиПоТипу(). У найденного объекта метаданных уже можно будет получить ПолноеИмя().
Рассмотрим пример кода для этого подхода.
// Пример для реквизитов справочника "Номенклатура"
Для Каждого Реквизит Из Метаданные.Справочники["Номенклатура"].Реквизиты Цикл
Для Каждого Тип Из Реквизит.Тип.Типы() Цикл
// Используем Попытку, так как для примитивных типов (Число, Строка)
// вызов Новый(Тип) вызовет ошибку.
Попытка
// Создаем пустой объект (например, пустую ссылку)
ПустойОбъект = Новый(Тип);
// Находим объект метаданных по типу значения
НайденныеМетаданные = Метаданные.НайтиПоТипу(ТипЗнч(ПустойОбъект));
Если НайденныеМетаданные <> Неопределено Тогда
// Получаем полное имя, например, "Справочник.Организации"
ПолноеИмяТипа = НайденныеМетаданные.ПолноеИмя();
// Добавляем "Ссылка" для получения нужного формата
// (требуется дополнительная логика для разных видов объектов)
Сообщить(СтрЗаменить(ПолноеИмяТипа, ".", "Ссылка."));
КонецЕсли;
Исключение
// Сюда мы попадем, если тип примитивный.
// Можно получить его строковое представление через СтрЗаменить(Строка(Тип), """", "")
Сообщить(Тип);
КонецПопытки
КонецЦикла;
КонецЦикла;
Недостатки этого способа:
Попытка-Исключение для разделения обработки ссылочных и примитивных типов.Новый(Тип)) в цикле — относительно медленная операция..ПолноеИмя() вернет строку вида Справочник.Организации. Для приведения ее к формату СправочникСсылка.Организации потребуется дополнительная обработка строк.Таким образом, несмотря на работоспособность второго метода, решение на основе XMLТип() является предпочтительным для большинства практических задач по анализу метаданных.