Как-то мне понадобилось при обработке сформированного отчета понять к какому уровню группировки относится та или иная ячейка. Тут нужно напомнить, что группировки, во-первых, бывают многоуровневыми, а, во-вторых, горизонтальными и вертикальными (на скриншотах виден пример такого отчета). Помимо этого, группировки по колонкам одной строки, могут отличаться от группировок колонок другой строки, если строки объединены в свой формат колонок (это когда колонки в строках имеет различную ширину в разных строках).
Попытался найти что-то уже кем-то разработанное решение, но обычно все обсуждения сводились к альтернативным способам, например, анализировать настройки СКД или значения расшифровок в ячейки. Мне же не хотелось концентрироваться на том как был сформирован табличный документ, а просто взять сформированный табличный документ даже просто из файла *.mxl и определять уровень группировки любой ячейки.
Единственное, что я нашёл подходящее для моей задачи, это была вот эта статья: //infostart.ru/public/182115/. В данной разработке использовалась функция определения уровня ячейки. Но при использовании обнаружил следующее:
- в ней нет функции определении уровня группировок колонок, а только функция определения уровня группировки строк;
- при наличии в табличном документе группировок колонок функция определения уровня строк перестаёт работать.
Далее я натолкнулся на хорошую статья //infostart.ru/public/562724/, где используется сериализация и разбор структуры табличного документа. И мне захотелось просто сделать функции, куда передаёшь координаты ячейки и получаешь уровни колонок и строк группировок.
Итак, у вас есть форма обработки и на ней размещен реквизит формы табличный документ (ТабДок), далее становимся на любую ячейку и нажимаем кнопку "ПолучитьУровниТекущейЯчейки". Выводятся сообщения с номерами уровней группировки строк и колонок ячейки. Если ячейка не входят в группировки, то её уровень равен. 1 (единица).
Вот код:
&НаКлиенте
Процедура ПолучитьУровниТекущейЯчейки(Команда)
//ТабДок - рекизит на форме (Табличный документ)
//и вынесен на форму в элемент "ТабДок"
НомерСтроки = Элементы.ТабДок.ТекущаяОбласть.Верх;
НомерКолонки = Элементы.ТабДок.ТекущаяОбласть.Лево;
УровеньЯчейки = ПолучитьУровеньГруппировкиЯчейки(ТабДок,НомерСтроки,НомерКолонки);
Сообщить("Уровни группировок ячейки (" + НомерСтроки + "," + НомерКолонки + "," + НомерСтроки +"," + НомерКолонки + ")");
Сообщить(Символы.Таб + "Уровень строки: " + УровеньЯчейки.УровеньСтроки);
Сообщить(Символы.Таб + "Уровень колонки: " + УровеньЯчейки.УровеньКолонки);
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьУровеньГруппировкиЯчейки(ТабДок, НомерСтроки,НомерКолонки)
Перем УровеньЯчейки;
УровеньЯчейки = Новый Структура("УровеньСтроки,УровеньКолонки",1,1);
мЗапись = Новый ЗаписьXML;
мЗапись.УстановитьСтроку("UTF-8");
СериализаторXDTO.ЗаписатьXML(мЗапись,ТабДок);
ТекстXML = мЗапись.Закрыть();
мЧтение = Новый ЧтениеXML;
мЧтение.УстановитьСтроку(ТекстXML);
ПострDOM = Новый ПостроительDOM;
ДанныеDOM = ПострDOM.Прочитать(мЧтение);
//уровни строк
ТаблицаУровнейПоСтрокам = ПолучитьТаблицуУровнейПоСтрокам(ДанныеDOM);
строкаУровняПоСтрокам = ТаблицаУровнейПоСтрокам.Найти(НомерСтроки,"Номер");
Если строкаУровняПоСтрокам <> Неопределено Тогда
УровеньЯчейки.УровеньСтроки = строкаУровняПоСтрокам.Уровень;
КонецЕсли;
//уровни колонок
ТаблицаУровнейПоКолонкам = ПолучитьТаблицуУровнейПоКолонкам(ДанныеDOM);
строкиУровнейКолонокПоНомерамСтрок = ТаблицаУровнейПоКолонкам.НайтиСтроки(Новый Структура("НомерСтроки,ЕстьУровни", НомерСтроки,Истина));
Если строкиУровнейКолонокПоНомерамСтрок.Количество() > 0 Тогда
ТаблицаКолонок = строкиУровнейКолонокПоНомерамСтрок[0].ТаблицаКолонок;
строкаУровняКолонки = ТаблицаКолонок.Найти(НомерКолонки, "Номер");
Если строкаУровняКолонки <> Неопределено Тогда
УровеньЯчейки.УровеньКолонки = строкаУровняКолонки.Уровень;
КонецЕсли;
КонецЕсли;
Возврат УровеньЯчейки;
КонецФункции
&НаСервереБезКонтекста
Функция ПолучитьТаблицуУровнейПоСтрокам(ДанныеDOMТабДок)
ТаблицаУровней = Новый ТаблицаЗначений;
ТаблицаУровней.Колонки.Добавить("Номер",Новый ОписаниеТипов("Число",Новый КвалификаторыЧисла(10,0)));
ТаблицаУровней.Колонки.Добавить("Уровень",Новый ОписаниеТипов("Число",Новый КвалификаторыЧисла(10,0)));
УзлыУровнейDOMТабДок = ДанныеDOMТабДок.ПолучитьЭлементыПоИмени("vg");
ПредКонецГруппировки = 0;
Для инд = 0 по УзлыУровнейDOMТабДок.Количество() - 1 Цикл
УзелГруппы = УзлыУровнейDOMТабДок[инд];
НачалоГруппировки = 0;
КонецГруппировки = 0;
Для н = 0 По УзелГруппы.ДочерниеУзлы.Количество() - 1 Цикл
ПодУзел = УзелГруппы.ДочерниеУзлы[н];
Если ПодУзел.ИмяУзла = "b" Тогда
НачалоГруппировки = Число(СокрЛП(ПодУзел.ТекстовоеСодержимое));
ИначеЕсли ПодУзел.ИмяУзла = "e" Тогда
КонецГруппировки = Число(СокрЛП(ПодУзел.ТекстовоеСодержимое));
КонецЕсли;
КонецЦикла;
Если НачалоГруппировки = 0 Тогда Продолжить КонецЕсли;
// если конца группировки не оказалось, то одна позиция в подгруппе
Если КонецГруппировки = 0 Тогда
КонецГруппировки = НачалоГруппировки
КонецЕсли;
//конец область увеличить нужно на 1
КонецГруппировки = КонецГруппировки + 1;
РодительскийУровень = 0;
Для Номер = НачалоГруппировки по КонецГруппировки Цикл
строкаТаблицы = ТаблицаУровней.Найти(Номер, "Номер");
Если строкаТаблицы = Неопределено Тогда
строкаТаблицы = ТаблицаУровней.Добавить();
строкаТаблицы.Номер = Номер;
строкаТаблицы.Уровень = РодительскийУровень + 1;
Если Номер = НачалоГруппировки Тогда
РодительскийУровень = 1;
КонецЕсли;
Иначе
Если Номер = НачалоГруппировки Тогда
РодительскийУровень = строкаТаблицы.Уровень
Иначе
строкаТаблицы.Уровень = РодительскийУровень + 1;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЦикла;
Возврат ТаблицаУровней;
КонецФункции
&НаСервереБезКонтекста
Функция ПолучитьТаблицуУровнейПоКолонкам(ДанныеDOMТабДок)
ТаблицаУровней = Новый ТаблицаЗначений;
ТаблицаУровней.Колонки.Добавить("НомерСтроки",Новый ОписаниеТипов("Число",Новый КвалификаторыЧисла(10,0)));
ТаблицаУровней.Колонки.Добавить("columnsID",Новый ОписаниеТипов("Строка",Новый КвалификаторыСтроки(36)));
ТаблицаУровней.Колонки.Добавить("ТаблицаКолонок");
ТаблицаУровней.Колонки.Добавить("Уровень",Новый ОписаниеТипов("Число",Новый КвалификаторыЧисла(10,0)));
ТаблицаУровней.Колонки.Добавить("ЕстьУровни",Новый ОписаниеТипов("Булево"));
//Определяем сколько строк
//и идентификатор колонок columnsID, которые будут заполнены в тех строках
//где своё количество колонок (новый формат строк)
УзлыУровнейDOMТабДок = ДанныеDOMТабДок.ПолучитьЭлементыПоИмени("rowsItem");
Для инд = 0 по УзлыУровнейDOMТабДок.Количество() - 1 Цикл
УзелГруппы = УзлыУровнейDOMТабДок[инд];
строкаТаблицыНомерСтроки = ТаблицаУровней.Добавить();
ТаблицаКолонок = Новый ТаблицаЗначений;
ТаблицаКолонок.Колонки.Добавить("Номер",Новый ОписаниеТипов("Число",Новый КвалификаторыЧисла(10,0)));
ТаблицаКолонок.Колонки.Добавить("Уровень",Новый ОписаниеТипов("Число",Новый КвалификаторыЧисла(10,0)));
строкаТаблицыНомерСтроки.ТаблицаКолонок = ТаблицаКолонок;
Для н = 0 По УзелГруппы.ДочерниеУзлы.Количество() - 1 Цикл
ПодУзел = УзелГруппы.ДочерниеУзлы[н];
Если ПодУзел.ИмяУзла = "index" Тогда
строкаТаблицыНомерСтроки.НомерСтроки = Число(ПодУзел.ТекстовоеСодержимое) + 1;
ИначеЕсли ПодУзел.ИмяУзла = "row" Тогда
ПодУзел2 = ПодУзел.ДочерниеУзлы;
Для м = 0 по ПодУзел.ДочерниеУзлы.Количество() - 1 Цикл
ПодУзел2 = ПодУзел.ДочерниеУзлы[м];
Если ПодУзел2.ИмяУзла = "columnsID" Тогда
строкаТаблицыНомерСтроки.columnsID = СокрЛП(ПодУзел.ТекстовоеСодержимое);
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЦикла;
КонецЦикла;
УзлыУровнейDOMТабДок = ДанныеDOMТабДок.ПолучитьЭлементыПоИмени("hg");
Для инд = 0 по УзлыУровнейDOMТабДок.Количество() - 1 Цикл
УзелГруппы = УзлыУровнейDOMТабДок[инд];
columnsID = Неопределено;
НачалоГруппировки = 0;
КонецГруппировки = 0;
Для н = 0 По УзелГруппы.ДочерниеУзлы.Количество() - 1 Цикл
ПодУзел = УзелГруппы.ДочерниеУзлы[н];
Если ПодУзел.ИмяУзла = "columnsID" Тогда
columnsID = СокрЛП(ПодУзел.ТекстовоеСодержимое);
ИначеЕсли ПодУзел.ИмяУзла = "b" Тогда
НачалоГруппировки = Число(СокрЛП(ПодУзел.ТекстовоеСодержимое));
ИначеЕсли ПодУзел.ИмяУзла = "e" Тогда
КонецГруппировки = Число(СокрЛП(ПодУзел.ТекстовоеСодержимое));
КонецЕсли;
КонецЦикла;
Если НачалоГруппировки = 0 Тогда Продолжить КонецЕсли;
// если конца группировки не оказалось, то одна позиция в подгруппе
Если КонецГруппировки = 0 Тогда
КонецГруппировки = НачалоГруппировки
КонецЕсли;
//конец область увеличить нужно на 1
КонецГруппировки = КонецГруппировки + 1;
строкиКолонки = ТаблицаУровней.НайтиСтроки(Новый Структура("columnsID", columnsID));
ПредКонецГруппировки = 0;
Для НомерСтроки = 0 по строкиКолонки.Количество() - 1 Цикл
строкиКолонки.Получить(НомерСтроки).ЕстьУровни = Истина;
ТаблицаКолонок = строкиКолонки.Получить(НомерСтроки).ТаблицаКолонок;
РодительскийУровень = 0;
Для Номер = НачалоГруппировки по КонецГруппировки Цикл
строкаТаблицы = ТаблицаКолонок.Найти(Номер, "Номер");
Если строкаТаблицы = Неопределено Тогда
строкаТаблицы = ТаблицаКолонок.Добавить();
строкаТаблицы.Уровень = РодительскийУровень + 1;
строкаТаблицы.Номер = Номер;
Если Номер = НачалоГруппировки Тогда
РодительскийУровень = 1;
КонецЕсли;
Иначе
Если Номер = НачалоГруппировки Тогда
РодительскийУровень = строкаТаблицы.Уровень
Иначе
строкаТаблицы.Уровень = РодительскийУровень + 1;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецЦикла;
Возврат ТаблицаУровней;
КонецФункции
Проверял работает на 8.3, 8.2, должно работать и на 8.1.
Не претендую на лаконичность кода, хотелось, чтобы бы всё было понятно.