Как прочитать файл MXL с несколькими таблицами и выгрузить их в таблицы значений?

Программист 1С v8.3 (Управляемые формы) 1С:Зарплата и Управление Персоналом IT и автоматизация бизнеса
← На главную

При работе с типовыми отчетами (например, из конфигурации 1С:Зарплата и Управление Персоналом) часто возникает ситуация, когда один файл .mxl или выгруженный из него Excel содержит «кашу» из нескольких таблиц. Платформа 1С не предоставляет встроенного метода «прочитать всё сразу в одну таблицу значений», так как структура данных в разных блоках может отличаться. В этой статье мы подробно разберем, как программно идентифицировать границы таблиц и преобразовать их в объекты ТаблицаЗначений.

Метод 1: Идентификация таблиц по границам ячеек

Если таблицы внутри документа визуально отделены друг от друга рамками (границами), мы можем использовать это программно. Проанализируем алгоритм, который обходит ТабличныйДокумент и ищет ячейки, у которых включено отображение линий. Это позволяет динамически определять координаты начала и конца каждой таблицы.

Рассмотрим пример кода, реализующего этот подход:


// Предположим, ТД - это уже прочитанный ТабличныйДокумент
МассивТаблиц = Новый Массив;
НачалоТаблицы = Ложь;

Для стр = 1 По ТД.ВысотаТаблицы Цикл
    Для Кол = 1 По ТД.ШиринаТаблицы Цикл
        // Проверяем наличие левой границы как признак начала таблицы
        Если Не ТД.Область(стр, кол).ГраницаСлева.ТипЛинии = ТипЛинииЯчейкиТабличногоДокумента.НетЛинии И Не НачалоТаблицы Тогда
            ПараметрыТаблицы = Новый Структура("Верх, Лево, Низ, Право", стр, кол, 0, 0);
            НачалоТаблицы = Истина;
            
            // Ищем нижнюю границу таблицы по той же колонке
            Для ВнутрСтр = стр По ТД.ВысотаТаблицы Цикл
                Если ТД.Область(ВнутрСтр, кол).ГраницаСлева.ТипЛинии = ТипЛинииЯчейкиТабличногоДокумента.НетЛинии Тогда
                    ПараметрыТаблицы.Низ = ВнутрСтр - 1;
                    
                    // Ищем правую границу, обходя колонки в найденной строке
                    Для ВнутрКол = кол По ТД.ШиринаТаблицы Цикл
                        Если ТД.Область(ПараметрыТаблицы.Низ, ВнутрКол).ГраницаСправа.ТипЛинии = ТипЛинииЯчейкиТабличногоДокумента.НетЛинии Тогда
                            ПараметрыТаблицы.Право = ВнутрКол - 1;
                            Прервать;
                        КонецЕсли;
                    КонецЦикла;
                    
                    // Конвертируем область в Таблицу Значений
                    ПЗ = Новый ПостроительЗапроса;
                    ОбластьДляВыгрузки = ТД.Область(ПараметрыТаблицы.Верх, ПараметрыТаблицы.Лево, ПараметрыТаблицы.Низ, ПараметрыТаблицы.Право);
                    ПЗ.ИсточникДанных = Новый ОписаниеИсточникаДанных(ОбластьДляВыгрузки);
                    ПЗ.Выполнить();
                    МассивТаблиц.Добавить(ПЗ.Результат.Выгрузить());
                    
                    НачалоТаблицы = Ложь;
                    Прервать;
                КонецЕсли;
            КонецЦикла;
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

В данном примере мы используем объект ПостроительЗапроса (или ПостроительОтчета) для быстрой конвертации Область в РезультатЗапроса. Это избавляет нас от необходимости вручную создавать колонки в ТаблицаЗначений и типизировать их.

Метод 2: Поиск по ключевым словам (Якорям)

Часто границы таблиц заданы неявно, или линии отсутствуют. В этом случае мы можем искать начало каждой таблицы по уникальным заголовкам колонок. Проанализируем ситуацию: если мы знаем, что первая таблица начинается со слова «Сотрудник», а вторая — со слова «Подразделение», мы можем использовать метод НайтиТекст().

Разберем этот процесс по шагам:

  1. Используем метод ТД.НайтиТекст("ИскомыйЗаголовок"). Он вернет ячейку (область), с которой начинается таблица.
  2. От найденной ячейки определяем ширину таблицы, проходя вправо до первой пустой ячейки.
  3. Определяем высоту таблицы, проходя вниз до первой пустой строки или до изменения формата ячеек.
  4. Выделяем найденный диапазон и выгружаем его аналогично первому методу.

Метод 3: Чтение через объект DOM (XML)

Для продвинутых разработчиков существует способ работы с файлом .mxl как со структурированным XML-документом. Формат .mxl по сути является XML-файлом, упакованным специальным образом. Выясним причину, почему это эффективно: при работе с DOMDocument мы можем обращаться к узлам таблиц напрямую, не тратя ресурсы на визуальную отрисовку документа в памяти 1С.

Для этого используется объект ЧтениеXML и последующий анализ узлов. В структуре XML таблицы обычно разделены тегами областей, что позволяет точно сегментировать данные даже без анализа визуальных границ.

Метод 4: Работа с Excel через COM-соединение

Если файл уже сохранен в формате 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С не делает всю работу автоматически, сочетание методов обхода ячеек и использования ПостроителяОтчета позволяет эффективно превратить любой сложный отчет в набор структурированных таблиц для дальнейшей обработки.

← На главную