При разработке сложных отчетов, конструкторов печатных форм или механизмов динамического заполнения макетов программисты часто сталкиваются с задачей рефлексии: необходимо узнать, какие именно параметры заложены в ту или иную область ТабличныйДокумент. Разбираясь в том, как устроена объектная модель печатной формы, можно лучше понять внутреннюю логику работы с макетами и областями. По умолчанию встроенный язык 1С предоставляет доступ к коллекции Параметры, но она не позволяет просто «перечислить» имена всех доступных параметров в конкретной области макета так же легко, как мы перебираем ключи структуры. В этой статье мы подробно разберем все существующие способы решения этой задачи: от прямого перебора ячеек до низкоуровневого анализа XML-данных.
Самый надежный и понятный способ — это итерация по всем ячейкам целевой области. Мы проанализируем каждую ячейку, проверим ее свойство Заполнение и извлечем данные. Рассмотрим этот алгоритм подробнее.
Каждая ячейка (область) может иметь один из трех типов заполнения: Текст, Параметр или Шаблон. Нас интересуют последние два. Если в ячейке установлен тип Параметр, то имя параметра хранится непосредственно в свойстве Параметр. Если же установлен Шаблон, то нам придется «распарсить» строку текста, чтобы найти фрагменты, заключенные в квадратные скобки.
Разберем реализацию функции, которая возвращает список уникальных имен параметров:
Функция ПолучитьСписокПараметровОбласти(ОбластьМакета) Экспорт
// Используем Соответствие для хранения уникальных имен
// Это эффективнее, чем поиск в массиве на каждой итерации
НайденныеПараметры = Новый Соответствие;
// Определяем границы области
Для НомерСтроки = 1 По ОбластьМакета.ВысотаТаблицы Цикл
Для НомерКолонки = 1 По ОбластьМакета.ШиринаТаблицы Цикл
// Получаем конкретную ячейку
ТекущаяЯчейка = ОбластьМакета.Область(НомерСтроки, НомерКолонки, НомерСтроки, НомерКолонки);
// Анализируем тип заполнения
Если ТекущаяЯчейка.Заполнение = ТипЗаполненияОбластиТабличногоДокумента.Параметр Тогда
Если ЗначениеЗаполнено(ТекущаяЯчейка.Параметр) Тогда
НайденныеПараметры.Вставить(ТекущаяЯчейка.Параметр, Истина);
КонецЕсли;
ИначеЕсли ТекущаяЯчейка.Заполнение = ТипЗаполненияОбластиТабличногоДокумента.Шаблон Тогда
// Для шаблонов вызываем вспомогательную функцию парсинга
ИзвлечьПараметрыИзТекстаШаблона(ТекущаяЯчейка.Текст, НайденныеПараметры);
КонецЕсли;
КонецЦикла;
КонецЦикла;
// Преобразуем ключи соответствия в массив
Результат = Новый Массив;
Для Каждого Запись Из НайденныеПараметры Цикл
Результат.Добавить(Запись.Ключ);
КонецЦикла;
Возврат Результат;
КонецФункции
Обратите внимание на использование объекта Соответствие. Это важный момент: параметры в макете могут дублироваться (один и тот же параметр в разных ячейках), а Соответствие автоматически обеспечит нам уникальность имен ключей, что работает значительно быстрее, чем метод Найти() для массива.
Проанализируем ситуацию с шаблонами. Текст в шаблоне может выглядеть так: "Контрагент: [ИмяКонтрагента], Договор № [НомерДоговора]". Нам нужно извлечь все, что находится внутри скобок. Рассмотрим эффективный способ поиска подстрок:
Процедура ИзвлечьПараметрыИзТекстаШаблона(Знач ТекстШаблона, НайденныеПараметры)
Позиция = 1;
Пока Истина Цикл
Начало = Найти(Сред(ТекстШаблона, Позиция), "[");
Если Начало = 0 Тогда Прервать; КонецЕсли;
Начало = Позиция + Начало;
Конец = Найти(Сред(ТекстШаблона, Начало), "]");
Если Конец = 0 Тогда Прервать; КонецЕсли;
ИмяПараметра = Сред(ТекстШаблона, Начало, Конец - 1);
Если ЗначениеЗаполнено(ИмяПараметра) Тогда
НайденныеПараметры.Вставить(СокрЛП(ИмяПараметра), Истина);
КонецЕсли;
Позиция = Начало + Конец;
КонецЦикла;
КонецПроцедуры
Для более продвинутых решений мы рекомендуем использовать регулярные выражения через VBScript.RegExp, что позволит избежать сложных циклов и сделать код более лаконичным.
Выясним причину, по которой иногда лучше использовать сериализацию. Перебор ячеек в очень больших макетах (например, несколько тысяч строк) может занимать ощутимое время. В 1С есть возможность получить полное описание объекта в текстовом виде. Проанализируем два подхода:
ЧтениеXML, чтобы быстро найти все узлы с именем parameter.Рассмотрим пример с XML-анализом. Этот способ хорош тем, что нам не нужно вручную обходить каждую ячейку — мы перекладываем работу на быстрый парсер XML:
Функция ПолучитьПараметрыЧерезXML(Область)
СтрокаXML = ОбщегоНазначения.ЗначениеВСтрокуXML(Область);
Чтение = Новый ЧтениеXML;
Чтение.УстановитьСтроку(СтрокаXML);
Параметры = Новый Соответствие;
Пока Чтение.Прочитать() Цикл
// Ищем узлы, которые отвечают за параметры в формате XML 1С
Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента И Чтение.Имя = "parameter" Тогда
Параметры.Вставить(Чтение.ПрочитатьСтроку(), Истина);
КонецЕсли;
КонецЦикла;
Возврат Параметры;
КонецФункции
Если вы работаете в конфигурации на базе БСП (Библиотека Стандартных Подсистем) или в решениях вроде ЗУП 3.1, выясним, нет ли готовых инструментов. Разработчики 1С уже написали множество вспомогательных функций. Найти их поможет актуальный справочник по методам БСП (с примерами использования). Например, в некоторых модулях (в зависимости от версии БСП) доступны функции вида:
ОбщегоНазначенияБЗК.ПараметрыТабличногоДокумента(ТабличныйДокумент)
Перед тем как писать свой велосипед, обязательно проверьте глобальный поиск по конфигурации. Если же вам нужно разработать новый механизм печати по современным стандартам, изучите классический корректный пример внешней печатной формы на БСП 3.1. Высока вероятность, что в вашем распоряжении уже есть готовая экспортная функция.
Разберем ситуации, которые часто упускают из виду. Параметры могут находиться не только в ячейках сетки!
Графические объекты (Рисунки): В табличном документе могут быть картинки или надписи (текстовые боксы). У них также есть свойство Заполнение. Если вы хотите получить абсолютно все параметры макета, рассмотрите возможность перебора коллекции Область.Рисунки. Это особенно актуально, если при выводе не отображается текст сгруппированных текстовых блоков в итоговом документе.
Параметры расшифровки: Иногда ячейка содержит обычный текст, но в свойстве ПараметрРасшифровки указано имя параметра. Это нужно для того, чтобы при нажатии на ячейку система могла передать данные. Если ваша цель — полная рефлексия для создания универсального конструктора, обязательно проверяйте свойство Ячейка.ПараметрРасшифровки.
Проанализируем, как ускорить работу кода. Если макет огромный, а параметров в нем мало, вместо полного перебора можно использовать метод НайтиТекст(). Мы можем искать символ "[" (начало шаблона) и перемещать курсор поиска. Однако этот метод не поможет найти ячейки с типом Параметр, так как там текст в режиме конфигуратора может быть пустым до момента заполнения.
Для качественной проверки работы ваших алгоритмов на реальных данных удобно использовать универсальную форму отладки для внешних печатных форм.
Рекомендация: Для большинства практических задач наиболее сбалансированным решением является сочетание перебора ячеек в пределах ИспользуемогоДиапазона макета и использование Соответствия для накопления имен. Это гарантирует точность и достаточную скорость работы программы.