Работа с деревом значений в 1С 8.3
Дерево значений является одним из популярных типов данных, часто встречающихся на формах и конфигурации. Важным его преимуществом является заложенная платформой иерархичность, которой удобно воспользоваться в некоторых ситуациях, например, осуществить поиск по определенной группе элементов или получить отдельные итоговые суммы в различных категориях. Дерево значений в 1С – достаточно эффективный инструмент, достойный, чтобы разработчики тратили на его изучение свое время.
Размещение на форме и заполнение дерева значений
Чтобы на управляемой форме вывести дерево значений, необходимо добавить новый реквизит, выбрать нужный тип, добавить колонки и перетащить влево. На вопрос о добавлении колонок ответьте утвердительно, и перед вами предстанет общий вид дерева значений. Чтобы увидеть какие-либо записи, необходимо добавить строки дерева значений 1С с нужными данными.

Существует несколько способов заполнения дерева значений нужными нам свойствами с определенной иерархией. Самый простой вариант – заполнить вручную, последовательно добавляя элементы и внимательно самостоятельно соблюдая иерархию. Естественно, при большом количестве элементов данный вариант не должен рассматриваться разработчиками 1С. Данный способ вывода информации состоит из следующих операторов:
На стороне сервера:
-
Получение значения реквизита;
ДеревоРек = РеквизитФормыВЗначение("Дерево");
НоваяГруппа1 = ДеревоРек.Строки.Добавить(); НоваяГруппа1.ЭлементДерева = "Продукты"; НоваяГруппа1.НомерЭлемента = 1; НоваяГруппа2 = ДеревоРек.Строки.Добавить(); НоваяГруппа2.ЭлементДерева = "Мебель"; НоваяГруппа2.НомерЭлемента = 2; НовыйЭлемент1 = НоваяГруппа1.Строки.Добавить(); НовыйЭлемент1.ЭлементДерева = "Кефир"; НовыйЭлемент1.НомерЭлемента = 3; НовыйЭлемент2 = НоваяГруппа1.Строки.Добавить(); НовыйЭлемент2.ЭлементДерева = "Молоко"; НовыйЭлемент2.НомерЭлемента = 4;
ЗначениеВРеквизитФормы(ДеревоРек,"Дерево");
На стороне клиента:
-
Получение элементов дерева;
Группа1 = Дерево.ПолучитьЭлементы();
Строка1 = Группа1.Добавить(); Строка1.ЭлементДерева = "hand made"; Строка1.НомерЭлемента = 10; Группа1 = Строка1.ПолучитьЭлементы(); Подстрока1 = Группа1.Добавить(); Подстрока1.ЭлементДерева = "Шкатулка"; Подстрока1.НомерЭлемента = 12; Подстрока2 = Группа1.Добавить(); Подстрока2.ЭлементДерева = "Фенечка"; Подстрока2.НомерЭлемента = 13;

Таким способом можно оформить на управляемой форме 1С небольшое дерево значений или простую иерархию, используя цикл. Однако часто возникает задача представить на форме сложный иерархический справочник из базы данных. И здесь на помощь придет помещение результата запроса в дерево на форме. Алгоритм достаточно прост и логичен:
-
Создаем запрос и указываем нужные нам условия. Важно, чтобы псевдонимы совпадали с наименованием колонок дерева значений на форме;
Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ | Номенклатура.Ссылка КАК Номенклатура |ИЗ | Справочник.Номенклатура КАК Номенклатура | |УПОРЯДОЧИТЬ ПО | Номенклатура ИЕРАРХИЯ";
Данные = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией); ЗначениеВРеквизитФормы(Данные,"ДеревоНом")

При многократном использовании управляемой формы приходится очищать реквизиты. Не является исключением и дерево значений, если нам нужно получать актуальную информацию. Полностью очистить наш реквизит можно различными способами без особых усилий программиста:
-
На стороне клиента:
Дерево.ПолучитьЭлементы().Очистить();
ДеревоЗн = РеквизитФормыВЗначение("Дерево"); ДеревоЗн.Строки.Очистить(); ЗначениеВРеквизитФормы(ДеревоЗн, "Дерево");
Вышеперечисленные действия достаточно просты и не требуют усилий. Намного сложнее действия с конкретными строками, которые тоже необходимо использовать в работе. Ведь зачастую мы не будем иметь ни малейшего понятия о количестве строк в дереве, его иерархии, ее глубине и пр. Именно корректная работа с данными произвольной структуры требуется от качественно разработанной функциональности решения для анализа и обработки информации дерева значений.
Работа с заполненным деревом значений
В первую очередь, нужно научиться работать с данными, получая их из дерева. Для этого придется написать процедуру обхода строк дерева значений. Данные можно получить на сервере или клиенте, причем разница в алгоритмах будет небольшая. Ниже представлен алгоритм обхода дерева с краткими пояснениями операторов:
На клиентской стороне:
-
Вызываем процедуру, используя в качестве параметров строки дерева;
ОбойтиЭлементыДерева(Дерево.ПолучитьЭлементы());
&НаКлиенте Процедура ОбойтиЭлементыДерева(СтрокиДерева) Для каждого элемента Из СтрокиДерева Цикл Сообщить(элемента.ЭлементДерева); ВложенныеСтроки = элемента.ПолучитьЭлементы(); Если ВложенныеСтроки.Количество() > 0 Тогда ОбойтиЭлементыДерева(ВложенныеСтроки); КонецЕсли; КонецЦикла; КонецПроцедуры
На серверной стороне:
-
Получаем объект с формы;
ДеревоНаСервере = РеквизитФормыВЗначение("Дерево");
ОбойтиДеревоНаСервере(ДеревоНаСервере);
&НаСервере Процедура ОбойтиДеревоНаСервере(ДеревоНаСервере) Для каждого строка из ДеревоНаСервере.Строки цикл Сообщить(Строка.ЭлементДерева); Если Строка.Строки.Количество() > 0 Тогда ОбойтиДеревоНаСервере(Строка); КонецЕсли; КонецЦикла; КонецПроцедуры
Иногда в процессе обхода строк нам может потребоваться удалить что-либо. Для этого используется метод «Удалить(_параметр_)», для которого в качестве параметра может использоваться индекс или непосредственно строка. Так как в процессе обхода вы рассматриваете все строки по отдельности, не составит труда удалить некоторые из них. Будьте внимательны, так как при удалении строки удаляются все вложенные элементы.
Также достаточно распространенной задачей является преобразование дерева значений в таблицу значений. Так как нам нельзя терять иерархию, в таблице будет на 2 поля больше, чем в дереве – добавятся идентификатор и родитель. Заполнить таблицу с сохранением структуры мы сможем с помощью рекурсивной процедуры.
Целиком алгоритм состоит из:
-
Вызов процедуры с указанием начального идентификатора;
ПреобразоватьВТЗРекурсия(тДерево, тТаблица, Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000"));
&НаСервере Процедура ПреобразоватьВТЗРекурсия(тДерево, тТаблица, ГУИД) Для Каждого тСтр Из тДерево.Строки Цикл нСтр = тТаблица.Добавить(); нСтр.Колонка1 = тСтр.Колонка1; нСтр.Колонка2 = тСтр.Колонка2; нСтр.Родитель = ГУИД; нСтр.ГУИД = Новый УникальныйИдентификатор(); Если тСтр.Строки.Количество()>0 Тогда ПреобразоватьВТЗРекурсия(тСтр, тТаблица, нСтр.ГУИД); КонецЕсли; КонецЦикла; КонецПроцедуры
Зачастую пользователям бывает мало просто добавить дерево значений в 1С на управляемую форму. Постоянно поступают запросы, чтобы была возможность посмотреть всю структуру. Для этого придется развернуть дерево значений прямо на глазах у пользователя. В 1С это можно сделать, обойдя в цикле все строки и воспользовавшись одним из их методов:
ЭлементыДерева = Дерево.ПолучитьЭлементы(); Для каждого элемента из ЭлементыДерева цикл элементы.Дерево.Развернуть(элемента.ПолучитьИдентификатор(),Истина); КонецЦикла;

Также могут случаться ситуации, когда нужно свернуть имеющееся дерево. Для сворачивания конкретной строки можно воспользоваться методом «Свернуть(_Строка_)», аналогичным по синтаксису вышеописанному «Развернуть()». Чтобы полностью свернуть все дерево, придется воспользоваться рекурсивной функцией. Ее код достаточно прост и поддерживает общую методологию работы с деревом значений:
&НаКлиенте Процедура СвернутьДерево (ЭлементыДерева) Для Каждого элемента Из ЭлементыДерева Цикл ВлЭлементыЭлемента = элемента.ПолучитьЭлементы(); Если ВлЭлементыЭлемента.Количество() > 0 тогда СвернутьДерево(ВлЭлементыЭлемента); КонецЕсли; Элементы.Дерево.Свернуть(элемента.ПолучитьИдентификатор()); КонецЦикла; КонецПроцедуры

Одним из сложных нюансов, связанных с деревом значений, является отсутствие возможности отбора, когда родитель не удовлетворяет условию, а подчиненный элемент удовлетворяет. Нет однозначного ответа, что делать в подобных ситуациях, поэтому разработчики 1С решили не добавлять стандартную возможность фильтрации для дерева значений. Однако с этим можно справиться, разработав свою методику, например, скопировать дерево, удалить неподходящие значения и изменить иерархию.
Созданный в платформе 1С тип «Дерево значений» отлично подходит для задач отображения иерархических списков и не только. Пользуясь им грамотно, можно существенно сэкономить время и удовлетворить требования пользователей по визуализации необходимых им данных, легко загрузив данные в дерево, обойти их и отразить развернутый список на управляемой форме.
Как посмотреть дерево запросов при отладке, когда не работает ВыбратьСтроку()?
При отладке 1С в толстом клиенте, когда необходимо проанализировать содержимое переменной с типом дерево значений или таблица значений, можно использовать функционал «вычислить выражение» и расчитать значение «Дерево.ВыбратьСтроку()». При этом в окне предприятия откроется форма с деревом. В тонком клиенте эта возможность не доступна. Для анализа переменной с типом ДеревоЗначений (а так же РезультатЗапроса и ДеревоЗначений) можно воспользоваться функционалом обработки КонсольЗапросов. Порядок работы следующий: 1. Открыть обработку в режиме 1С Предприятие и скопировать ее на сервер
2. Скопировать текст вызова обработки из режима отладки
3. Поставить точку останова в месте, где сформирована коллекция и запустить отладку. 4. В точке останова вычислить выражение
5. вставить код из пункта 2.
5. Продолжить выполнение отладки. 6. После завершения отладки загрузить сформированные печатные формы с любой удобный каталог 
7. Открыть сформированную форму для просмотра
Все тоже самое на видео:

Пример вызова механизма печати коллекции из отладки:
ВнешниеОбработки.Создать("C:\Users\Evgeny\AppData\Local\Temp\consquery83.epf", Ложь).СформироватьПечатнуюФормуКоллекции(Коллекция, Новый Структура("ТипФайлаТаблицы", ТипФайлаТабличногоДокумента.XLSX))
где «Коллекция» — это произвольная коллекция одного из следующих типов <ТаблицаЗначений|ДеревоЗначений|РезультатЗапроса>
«ДополнительныеПараметры» — это Необязательный параметр типа структура со следующими необязательными ключами:
— ТипФайлаТаблицы: значение по умолчанию ТипФайлаТабличногоДокумента.MXL (ANSITXT, DOCX, HTML, HTML3, HTML4, HTML5, MXL, MXL7, ODS, PDF, TXT, XLS, XLS95, XLS97, XLSX)
— ПутьДляВыгрузкиПечатнойФормы : значение по умолчанию — «ПечФорма_» + результат выполнения стандартной функции ПолучитьИмяВременногоФайла() с расширением «MXL»
Дерево значений, которое негде посмотреть
Метод «ВыбратьСтроку» остался в золотом веке толстого клиента, но необходимость окинуть одним взглядом всё дерево порой возникает. Предлагаю простое решение в виде одной функции — вывода в текстовое представление.
Да, мы все понимаем, что модальные окна это плохо, а дерево значений не живёт на клиенте и не может быть отображено, но очень хочется следить за внешним видом и наполнением наших переменных хотя бы с целью отладки. Собственно, как раз для отладки «ВыбратьСтроку» у таблицы и дерева был незаменимым методом. Но, если таблицу значений можно более-менее адекватно увидеть в отладчике, то для иерархии дерева это совсем не вариант. Отладчик показывает содержимое крайне неудобно с точки зрения «единого просмотра».
Поэтому сделаем текстовое представление. Его можно выводить в окне сообщений и оттуда копировать, его можно сохранять в файл, его можно более-менее удобно посмотреть в отладчике. Разумеется, шрифт в том месте, где смотрите, должен быть моноширинным.
Никаких особых хитростей нет, кроме разве что одного места — определения максимального количества уровней в дереве. Признаю, что сделал это не самым оптимальным образом, через сериализацию (да ещё и всего дерева, когда хватило бы одной колонки) — можно и иначе, желающие да обрящут. Вот //infostart.ru/profile/28527/ наверняка придумал бы иной способ, верю.
Дизайн при желании можно отрегулировать самостоятельно, т.к. на вкус и цвет фломастеры бывают разные.
Используется вывод в текстовый документ с помощью текстового же макета:
// Выводит данные ДереваЗначений в ТекстовыйДокумент, пригодный к рассмотрению в отладчике, окне сообщений и показу.
//
// Параметры:
// рВетка — дерево значений, подлежащее выводу. Может иметь почти любую глубину иерархии, количество и тип колонок. Если хватит
// объявленных позиционных строк-заполнителей, всё поместится. Если иерархия слишком глубока, строки просто надо нарастить;
// рТекст — на входе должен быть равен Неопределено; на выходе по окончании работы содержит результатный текстовый документ;
// рПараметры — структура дополнительных настроек, допустимые ключи:
// Колонки — структура колонок, которые подлежат выводу. Если пуста или имеет тип, отличный от структуры, выводятся все колонки;
// если в ключах структуры указаны имена колонок, будут выведены только они. В значениях структуры можно передать строковое
// представление формата, согласно которому должны будут форматироваться выводимые значения. По умолчанию формата нет;
// ПоказыватьУровни — булево, управляет выводом №№ уровней (метод Уровень()), по умолчанию выключено;
// ШагОтступа — число, определяющее шаг в символах, используемый для показа псевдографики иерархии веток в дереве.
//
&НаСервереБезКонтекста
Процедура ВывестиДеревоЗначенийВТекст (Знач рВетка , рТекст ,Знач рПараметры =Неопределено)
Попытка
Если рТекст =Неопределено Тогда // первая итерация, шапочный вызов исходной части
//—————————————————————————————————————————
// Разбираем входные данные
Если ТипЗнч ( рВетка )<> Тип ( «ДеревоЗначений» ) Тогда Возврат КонецЕсли;
Если ТипЗнч ( рПараметры )<> Тип ( «Структура» ) Тогда рПараметры =Новый Структура КонецЕсли;
стрКолонок =?( рПараметры . Свойство ( «Колонки» ), рПараметры . Колонки ,Неопределено);
Если ТипЗнч ( стрКолонок )<> Тип ( «Структура» ) Тогда стрКолонок =Новый Структура КонецЕсли;
рПоказыватьУровни =?( рПараметры . Свойство ( «ПоказыватьУровни» ), рПараметры . ПоказыватьУровни ,Ложь); // затратное дело, кстати
рШагОтступа =?( рПараметры . Свойство ( «ШагОтступа» ), рПараметры . ШагОтступа , 2 ); // для отображения отступа в колонке иерархии
//—————————————————————————————————————————
// Определяем максимальное количество уровней
// Также можно получить максимальный уровень, «плоско» перебрав все строки (например, получив их через НайтиСтроки)
// и в цикле для каждой вызывая Уровень() и определяя максимум.
// Вариант через СКД и служебное поле «Уровень» ни на одной известной мне платформе не работоспособен (нехватка памяти).
//
//
//рДеревоДляТеста=КакНибудьСкопироватьДерево(рВетка);
//рДеревоДляТеста.Колонки.Вставить(0,»_Level»,Новый ОписаниеТипов(«Булево»)); // самый экономный вариант, с сохранением иерархии
//мНенужных=Новый Массив;
//Для й=1 По рДеревоДляТеста.Колонки.Количество()-1 Цикл
// мНенужных.Добавить(рДеревоДляТеста.Колонки[й]);
//КонецЦикла;
//Для каждого кол Из мНенужных Цикл
// рДеревоДляТеста.Колонки.Удалить(кол);
//КонецЦикла;
//
рДеревоДляТеста = рВетка ; // пока сериализуем прямо всё дерево (неоптимально, но. )
рЗапись =Новый ЗаписьXML ;
рЗапись . УстановитьСтроку ();
СериализаторXDTO . ЗаписатьXML ( рЗапись , рДеревоДляТеста );
стро = рЗапись . Закрыть ();
//
стро = СтрЗаменить ( стро , «xmlns color: red;»>, «xmlns:myns1C color: red;»>); // иначе не будет работать XPath
//
рЧтение =Новый ЧтениеXML ;
рЧтение . УстановитьСтроку ( стро );
постр =Новый ПостроительDOM ;
рДокументДОМ = постр . Прочитать ( рЧтение );
рВыражение = «/ValueTree/row» ; максКолвоУровней = 1 ;
рРазыменователь =Новый РазыменовательПространствИменDOM ( рДокументДОМ );
Пока Истина Цикл
#Если Клиент Тогда
ОбработкаПрерыванияПользователя ();
#КонецЕсли
рРезультат = рДокументДОМ . ВычислитьВыражениеXPath ( рВыражение , рДокументДОМ , рРазыменователь , ТипРезультатаDOMXPath . Любой );
Если рРезультат . ПолучитьСледующий ()=Неопределено Тогда Прервать КонецЕсли;
рВыражение = рВыражение + «/row» ;
максКолвоУровней = максКолвоУровней + 1 ;
КонецЦикла;
максКолвоУровней = максКолвоУровней — 1 ; // можно и так: СтрЧислоВхождений(рВыражение,»/row»)-1;
//—————————————————————————————————————————
// готовим исходный макет вывода
строПробелы = » » ;
строРазделители = «============================================================================================== color: red;»>;
строОтступы = «___________________________________________________________________________________________» ; // тут нужны чуть для другого
//
секШапка1 = «|[_HCS» + Лев ( строПробелы , максКолвоУровней * рШагОтступа )+ «]|» ; // HierarchyColumnShow
секГорРазделитель1 = «|» + Лев ( строОтступы , максКолвоУровней * рШагОтступа + 6 )+ «|» ; // здесь именно Отступы!
рШиринаКолонкиИерархии = СтрДлина ( секШапка1 )- 2 ;
строПолейШапки = «#Поле _HCS
| #Выравнивание Центр» ;
строПолейЗаписи = «» ;
//
Если рПоказыватьУровни Тогда
секШапка1 = секШапка1 + «[_Level]|» ;
секГорРазделитель1 = секГорРазделитель1 + Лев ( строРазделители , 8 )+ «|» ;
строПолейШапки = строПолейШапки + »
|#Поле _Level
| #Выравнивание Центр» ;
строПолейЗаписи = «#Поле _Level
| #Выравнивание Центр
| #Забивать Истина» ;
КонецЕсли;
//
мИменКолонок =Новый Массив ;
Для каждого кол Из рВетка . Колонки Цикл
Если стрКолонок . Количество ()<> 0 и не стрКолонок . Свойство ( кол . Имя ) Тогда Продолжить КонецЕсли; // чётко указаны конкретные колонки
рДлинаИмениКолонки = СтрДлина ( кол . Имя );
рНужнаяШирина = Макс (?( кол . Ширина < 3 , 10 , кол . Ширина ), рДлинаИмениКолонки );
// к сожалению, ключевое слово «#Поля» неприменимо — платформа падает — поэтому делаем всё сами
секШапка1 = секШапка1 + «[» + кол . Имя + Лев ( строПробелы , рНужнаяШирина — рДлинаИмениКолонки )+ «]|» ;
секГорРазделитель1 = секГорРазделитель1 + Лев ( строРазделители , рНужнаяШирина + 1 )+ «=|» ;
строПолейШапки = строПолейШапки + »
|#Поле » + кол . Имя + »
| #Выравнивание Центр» ;
рОписТипов = кол . ТипЗначения ;
Если рОписТипов . Типы (). Количество ()= 1 и рОписТипов . СодержитТип ( Тип ( «Булево» )) Тогда
рВыравнивание = «Центр» ;
ИначеЕсли рОписТипов . СодержитТип ( Тип ( «Число» )) Тогда
рВыравнивание = «Право» ;
ИначеЕсли рОписТипов . СодержитТип ( Тип ( «Строка» )) и рОписТипов . КвалификаторыСтроки . Длина = 0 Тогда
рВыравнивание = «ПоШирине» ;
Иначе
рВыравнивание = «Лево» ;
КонецЕсли;
строПолейЗаписи = строПолейЗаписи +?( ПустаяСтрока ( строПолейЗаписи ), «» , Символы . ПС )+ «#Поле » + кол . Имя + »
| #Выравнивание » + рВыравнивание ;
Попытка
Если ЗначениеЗаполнено ( стрКолонок [ кол . Имя ]) Тогда // указан формат, уточняющий показ колонки
строПолейЗаписи = строПолейЗаписи + »
| #Формат «»» + СокрЛП ( стрКолонок [ кол . Имя ])+ «»»» ;
КонецЕсли;
Исключение
КонецПопытки;
мИменКолонок . Добавить ( кол . Имя );
КонецЦикла;
секШапка2 = СтрЗаменить ( СтрЗаменить ( секШапка1 , «[» , «» );
секЗапись1 = секШапка1 ; секЗапись2 = секШапка2 ; // пусть они по дизайну пока не отличаются
секГорРазделитель2 = СтрЗаменить ( СтрЗаменить ( секГорРазделитель1 , » color: red;»>, «-» ), «|» , «+» );
// обработаем нормальное обрамление шапки колонки иерархии
секГорРазделитель1 = СтрЗаменить ( секГорРазделитель1 , «_» , » color: red;»>);
секГорРазделитель2 = СтрЗаменить ( секГорРазделитель2 , «_» , » » );
//
тМакет =Новый ТекстовыйДокумент ;
тМакет . ДобавитьСтроку ( «#Область Шапка» );
тМакет . ДобавитьСтроку ( строПолейШапки );
тМакет . ДобавитьСтроку ( секГорРазделитель1 );
тМакет . ДобавитьСтроку ( секШапка1 );
тМакет . ДобавитьСтроку ( секШапка2 );
тМакет . ДобавитьСтроку ( секГорРазделитель1 );
тМакет . ДобавитьСтроку ( «#КонецОбласти» );
тМакет . ДобавитьСтроку ( «» );
тМакет . ДобавитьСтроку ( «#Область Запись» );
тМакет . ДобавитьСтроку ( строПолейЗаписи );
тМакет . ДобавитьСтроку ( секЗапись1 );
тМакет . ДобавитьСтроку ( секЗапись2 );
тМакет . ДобавитьСтроку ( секГорРазделитель2 );
тМакет . ДобавитьСтроку ( «#КонецОбласти» );
рПараметры . Вставить ( «ИсходныйМакет» , тМакет ); // пусть будет
//—————————————————————————————————————————
// Запускаем вывод в итоговый документ
рТекст =Новый ТекстовыйДокумент ;
сек = тМакет . ПолучитьОбласть ( «Шапка» );
сек . Параметры . _HCS = «Иерархия» ;
Для каждого имякол Из мИменКолонок Цикл
кол = рВетка . Колонки [ имякол ];
сек . Параметры [ кол . Имя ]=?( ПустаяСтрока ( кол . Заголовок ), кол . Имя , кол . Заголовок );
КонецЦикла;
рТекст . Вывести ( сек );
//
пар =Новый Структура ;
пар . Вставить ( «МассивИмёнКолонок» , мИменКолонок );
пар . Вставить ( «ТекущаяСекция» , тМакет . ПолучитьОбласть ( «Запись» ));
пар . Вставить ( «ШиринаКолонкиИерархии» , рШиринаКолонкиИерархии );
пар . Вставить ( «ПоказыватьУровни» , рПоказыватьУровни );
пар . Вставить ( «Отступ» , 0 );
пар . Вставить ( «ШагОтступа» , рШагОтступа );
ВывестиДеревоЗначенийВТекст ( рВетка , рТекст , пар );
Иначе
// очередная итерация, вывод в текстовый документ
мИменКолонок = рПараметры . МассивИмёнКолонок ;
рСекция = рПараметры . ТекущаяСекция ;
рОтступ = рПараметры . Отступ ;
рШиринаКолонкиИерархии = рПараметры . ШиринаКолонкиИерархии ;
рПоказыватьУровни = рПараметры . ПоказыватьУровни ;
//
строОтступы = «_________________________________________________________________________________________________________» ;
строПробелы = » » ;
//
пар =Новый Структура ;
пар . Вставить ( «МассивИмёнКолонок» , мИменКолонок );
пар . Вставить ( «ТекущаяСекция» , рПараметры . ТекущаяСекция );
пар . Вставить ( «ШиринаКолонкиИерархии» , рШиринаКолонкиИерархии );
пар . Вставить ( «ПоказыватьУровни» , рПоказыватьУровни );
пар . Вставить ( «ШагОтступа» , рПараметры . ШагОтступа );
пар . Вставить ( «Отступ» , рОтступ + рПараметры . ШагОтступа );
//
Для каждого рПодветка Из рВетка . Строки Цикл
рСекция . Параметры . _HCS = Лев ( строПробелы , рОтступ )+ «\» + Лев ( строОтступы , рШиринаКолонкиИерархии — рОтступ — 1 );
Если рПоказыватьУровни Тогда
рСекция . Параметры . _Level = рПодветка . Уровень ();
КонецЕсли;
Для каждого имякол Из мИменКолонок Цикл
рСекция . Параметры [ имякол ]= рПодветка [ имякол ];
КонецЦикла;
рТекст . Вывести ( рСекция );
ВывестиДеревоЗначенийВТекст ( рПодветка , рТекст , пар )
КонецЦикла;
//
КонецЕсли;
Исключение
Сообщить ( «ВывестиДеревоЗначенийВТекст, ошибка: » + ОписаниеОшибки (), СтатусСообщения . ОченьВажное );
КонецПопытки;
КонецПроцедуры
Надеюсь, пригодится и упростит жизнь)









