При работе с типовыми отчетами (например, из конфигурации 1С:Зарплата и Управление Персоналом) часто возникает ситуация, когда один файл .mxl или выгруженный из него Excel содержит «кашу» из нескольких таблиц. Платформа 1С не предоставляет встроенного метода «прочитать всё сразу в одну таблицу значений», так как структура данных в разных блоках может отличаться. В этой статье мы подробно разберем, как программно идентифицировать границы таблиц и преобразовать их в объекты ТаблицаЗначений.
Если таблицы внутри документа визуально отделены друг от друга рамками (границами), мы можем использовать это программно. Проанализируем алгоритм, который обходит ТабличныйДокумент и ищет ячейки, у которых включено отображение линий. Это позволяет динамически определять координаты начала и конца каждой таблицы.
Рассмотрим пример кода, реализующего этот подход:
// Предположим, ТД - это уже прочитанный ТабличныйДокумент
МассивТаблиц = Новый Массив;
НачалоТаблицы = Ложь;
Для стр = 1 По ТД.ВысотаТаблицы Цикл
Для Кол = 1 По ТД.ШиринаТаблицы Цикл
// Проверяем наличие левой границы как признак начала таблицы
Если Не ТД.Область(стр, кол).ГраницаСлева.ТипЛинии = ТипЛинииЯчейкиТабличногоДокумента.НетЛинии И Не НачалоТаблицы Тогда
ПараметрыТаблицы = Новый Структура("Верх, Лево, Низ, Право", стр, кол, 0, 0);
НачалоТаблицы = Истина;
// Ищем нижнюю границу таблицы по той же колонке
Для ВнутрСтр = стр По ТД.ВысотаТаблицы Цикл
Если ТД.Область(ВнутрСтр, кол).ГраницаСлева.ТипЛинии = ТипЛинииЯчейкиТабличногоДокумента.НетЛинии Тогда
ПараметрыТаблицы.Низ = ВнутрСтр - 1;
// Ищем правую границу, обходя колонки в найденной строке
Для ВнутрКол = кол По ТД.ШиринаТаблицы Цикл
Если ТД.Область(ПараметрыТаблицы.Низ, ВнутрКол).ГраницаСправа.ТипЛинии = ТипЛинииЯчейкиТабличногоДокумента.НетЛинии Тогда
ПараметрыТаблицы.Право = ВнутрКол - 1;
Прервать;
КонецЕсли;
КонецЦикла;
// Конвертируем область в Таблицу Значений
ПЗ = Новый ПостроительЗапроса;
ОбластьДляВыгрузки = ТД.Область(ПараметрыТаблицы.Верх, ПараметрыТаблицы.Лево, ПараметрыТаблицы.Низ, ПараметрыТаблицы.Право);
ПЗ.ИсточникДанных = Новый ОписаниеИсточникаДанных(ОбластьДляВыгрузки);
ПЗ.Выполнить();
МассивТаблиц.Добавить(ПЗ.Результат.Выгрузить());
НачалоТаблицы = Ложь;
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЦикла;
КонецЦикла;
В данном примере мы используем объект ПостроительЗапроса (или ПостроительОтчета) для быстрой конвертации Область в РезультатЗапроса. Это избавляет нас от необходимости вручную создавать колонки в ТаблицаЗначений и типизировать их.
Часто границы таблиц заданы неявно, или линии отсутствуют. В этом случае мы можем искать начало каждой таблицы по уникальным заголовкам колонок. Проанализируем ситуацию: если мы знаем, что первая таблица начинается со слова «Сотрудник», а вторая — со слова «Подразделение», мы можем использовать метод НайтиТекст().
Разберем этот процесс по шагам:
ТД.НайтиТекст("ИскомыйЗаголовок"). Он вернет ячейку (область), с которой начинается таблица.Для продвинутых разработчиков существует способ работы с файлом .mxl как со структурированным XML-документом. Формат .mxl по сути является XML-файлом, упакованным специальным образом. Выясним причину, почему это эффективно: при работе с DOMDocument мы можем обращаться к узлам таблиц напрямую, не тратя ресурсы на визуальную отрисовку документа в памяти 1С.
Для этого используется объект ЧтениеXML и последующий анализ узлов. В структуре XML таблицы обычно разделены тегами областей, что позволяет точно сегментировать данные даже без анализа визуальных границ.
Если файл уже сохранен в формате Excel и содержит пустые строки между таблицами, рассмотрим вариант использования COM-объекта. Этот метод позволяет задействовать мощь движка Excel для поиска данных.
Посмотрим на пример логики поиска блоков данных:
Excel = Новый COMОбъект("Excel.Application");
Книга = Excel.Workbooks.Open(ПутьКФайлу);
Лист = Книга.Sheets(1);
// Используем метод End (аналог Ctrl+Arrow), чтобы прыгать через пустые области
НачалоТаблицы = Лист.Cells(1, 1);
Если ПустаяСтрока(НачалоТаблицы.Value) Тогда
НачалоТаблицы = НачалоТаблицы.End(-4121); // xlDown
КонецЕсли;
// Координаты можно получить так:
НомерСтроки = НачалоТаблицы.Row;
НомерКолонки = НачалоТаблицы.Column;
Важный момент: При чтении из Excel через 1С всегда учитывайте способ получения значений. Чтобы избежать преобразования чисел в строки с пробелами-разделителями (например, "1 000,00"), при чтении напрямую в ТабличныйДокумент используйте параметр СпособЧтенияЗначений.Значение.
При реализации любого из подходов придерживайтесь следующих правил:
ТД.Области. Возможно, разработчик уже присвоил имена нужным секциям, и их можно прочитать напрямую по имени ТД.Область("СоставОтчета").Таким образом, хотя 1С не делает всю работу автоматически, сочетание методов обхода ячеек и использования ПостроителяОтчета позволяет эффективно превратить любой сложный отчет в набор структурированных таблиц для дальнейшей обработки.