При работе с Системой Компоновки Данных (СКД) часто возникают ситуации, когда стандартных возможностей настроек отчета недостаточно для реализации сложной бизнес-логики. Иногда требуется произвести дополнительные вычисления или изменить оформление в уже сформированном ТабличныйДокумент, ориентируясь на конкретные уровни группировок. В этой статье мы подробно разберем, как программно определить уровень иерархии строк в готовом отчете и произвести их обход.
Проанализируем самый надежный способ идентификации строк. Чтобы не «гадать», к какому уровню относится строка в табличном документе, мы можем передать номер уровня напрямую из СКД в расшифровку ячейки. Это позволит нам при обходе документа мгновенно получать метаданные строки.
Рассмотрим пошагово, как это реализовать:
Уровень().Расшифровка.Пример кода для обхода сформированного документа (подготовить каркас подобного алгоритма поможет ИИ-помощник в консоли кода):
Для НомерСтроки = 1 По ДокументРезультат.ВысотаТаблицы Цикл
Область = ДокументРезультат.Область(НомерСтроки, 1); // Берем ячейку в первой колонке
ЗначениеРасшифровки = Область.Расшифровка;
// Получаем данные расшифровки
Если ТипЗнч(ЗначениеРасшифровки) = Тип("ИдентификаторРасшифровкиКомпоновкиДанных") Тогда
// Здесь можно извлечь уровень, если он был передан
// На основе уровня выполняем вычисления в нужной колонке
КонецЕсли;
КонецЦикла;
Выясним причину, по которой иногда лучше перехватывать данные в момент вывода, а не после. Использование ПроцессорВывода.Вывести(ПроцессорКомпоновки) сразу выдает весь результат. Однако, если мы будем использовать цикл с методом Следующий(), мы сможем контролировать каждый элемент компоновки.
Рассмотрим пример реализации поэлементного вывода:
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
Пока Истина Цикл
ЭлементРезультата = ПроцессорКомпоновки.Следующий();
Если ЭлементРезультата = Неопределено Тогда
Прервать;
КонецЕсли;
// Анализируем тип элемента
Если ЭлементРезультата.ТипЭлемента = ТипЭлементаРезультатаКомпоновкиДанных.НачалоГруппировки Тогда
// Проверяем уровень или имя группировки
Если ЭлементРезультата.ЗначенияПараметров.Найти("Уровень") = 2 Тогда
// Совершаем действия для группировки 2-го уровня
КонецЕсли;
КонецЕсли;
ПроцессорВывода.ВывестиЭлемент(ЭлементРезультата);
КонецЦикла;
Если нам достался уже сформированный ТабличныйДокумент и мы не можем менять настройки СКД, воспользуемся методом анализа XML-структуры. Этот способ считается «хакерским», но он крайне эффективен, так как при сохранении документа в XML 1С записывает уровни группировок строк в атрибуты.
Посмотрим на алгоритм действий:
ТабличныйДокумент во временный файл XML.ЧтениеXML.<row>), у которых есть атрибут outlineLevel.Значение outlineLevel="1" соответствует второму уровню иерархии (индексация в XML начинается с 0). Это позволяет быстро составить карту строк документа с привязкой к их уровням.
Проанализируем интересную особенность платформы. У объекта ТабличныйДокумент есть метод ПоказатьУровеньГруппировокСтрок(Уровень). Мы можем использовать его для идентификации строк.
Алгоритм решения задачи:
ДокументРезультат.ПоказатьУровеньГруппировокСтрок(1). Теперь все строки ниже 1-го уровня стали невидимыми.ДокументРезультат.ПоказатьУровеньГруппировокСтрок(2). Теперь видны строки 1-го и 2-го уровней.Видимость изменилось с Ложь на Истина при переходе от 1 к 2 уровню, гарантированно являются строками 2-го уровня.Этот метод не требует изменения СКД и работает исключительно с визуальным представлением данных.
Если структура вашего отчета фиксирована, мы можем назначить конкретным группировкам Имя области в макете компоновки. Рассмотрим, как это упрощает жизнь программисту. В некоторых случаях архитектура требует использовать две разные схемы в одном отчете, что также влияет на структуру областей.
В схеме СКД на закладке Макеты можно создать макет группировки и указать для него уникальное имя. При выводе отчета 1С пометит соответствующие области в табличном документе этими именами. В коде пост-обработки вам достаточно будет обратиться к коллекции ДокументРезультат.Области, чтобы найти все вхождения нужной группировки по имени.
Если основной целью обхода документа является скорость вычислений (как упоминалось в Сообщении 3), то работа напрямую с ячейками ТабличныйДокумент — не самый лучший выбор. Доступ к ячейкам через Область(нС, нК) в больших документах работает медленно.
Рекомендуем следующий подход:
ТабличныйДокумент, а в ДеревоЗначений.Строки первого уровня, их вложенные коллекции Строки и так далее.ТабличныйДокумент или используем его как источник данных для финального отчета.Пример получения дерева:
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВДеревоЗначений;
ДеревоРезультат = Новый ДеревоЗначений;
ПроцессорВывода.УстановитьОбъект(ДеревоРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);
// Обход 2-го уровня
Для Каждого СтрокаУр1 Из ДеревоРезультат.Строки Цикл
Для Каждого СтрокаУр2 Из СтрокаУр1.Строки Цикл
// Здесь мы точно на 2-м уровне группировки
СтрокаУр2.Результат = СтрокаУр2.Параметр1 * Коэффициент;
КонецЦикла;
КонецЦикла;
Подводя итог, можно сказать, что выбор метода зависит от того, есть ли у вас доступ к изменению схемы СКД. Если есть — используйте скрытые поля или расшифровку. Если отчет «черный ящик» — используйте анализ видимости строк или XML-парсинг. Для задач высокой производительности всегда отдавайте предпочтение Дереву Значений.