Как программно создать иерархический нумерованный список в Word из 1С?

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

Создание сложных документов Microsoft Word из среды 1С — это классическая задача, с которой сталкиваются разработчики при автоматизации документооборота. Одной из самых трудоемких подзадач является формирование динамического иерархического списка, глубина которого заранее неизвестна и зависит от структуры данных (например, справочника или дерева значений). Основная сложность заключается в том, что обычного вывода текста недостаточно: необходимо, чтобы пункты были пронумерованы (1., 1.1., 1.1.1.), являлись заголовками и корректно отображались в панели навигации Word. Для комплексной автоматизации подобных процессов и исключения ручного труда можно использовать платформу One RPA для роботизации формирования документов.

В этой статье мы разберем проверенное решение, основанное на использовании COM-технологий, шаблонов стилей и рекурсивных алгоритмов 1С. Мы пройдем путь от подготовки данных до формирования финального документа.

Метод 1: Подготовка данных с использованием рекурсии

Прежде чем приступать к рисованию в Word, нам необходимо преобразовать иерархические данные 1С (например, справочник с группами и элементами) в плоский массив, сохранив при этом информацию об уровне вложенности каждого элемента. Рассмотрим, как это сделать с помощью рекурсивного обхода.

Для начала проанализируем запрос, который получает данные с учетом иерархии. Мы будем использовать конструкцию ИТОГИ ПО ... ИЕРАРХИЯ, которая позволяет эффективно выгрузить дерево в 1С.


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

Теперь разберем саму рекурсивную процедуру РазложитьДеревоРекурсивно. Она проходит по всем веткам дерева, увеличивая счетчик УровеньЗаголовка при каждом погружении глубже по иерархии.


&НаСервере
Процедура РазложитьДеревоРекурсивно(Строки, МассивСтрокСУровнями, УровеньРодителя)
    ТекУровень = УровеньРодителя + 1;
    Для Каждого Строка ИЗ Строки Цикл
        СтруктураСтроки = Новый Структура("НомерПункта, Порядок, Пояснение, СведенияПроекта, УровеньЗаголовка");
        ЗаполнитьЗначенияСвойств(СтруктураСтроки, Строка);
        СтруктураСтроки.УровеньЗаголовка = ТекУровень;
        МассивСтрокСУровнями.Добавить(СтруктураСтроки);
        
        // Рекурсивный вызов для следующего уровня
        РазложитьДеревоРекурсивно(Строка.Строки, МассивСтрокСУровнями, ТекУровень);
    КонецЦикла;
КонецПроцедуры

Метод 2: Формирование документа Word через стили и шаблоны

После того как данные подготовлены в массив с указанием уровней, мы приступаем к работе с COMОбъект("Word.Application"). Основная хитрость здесь заключается не в попытке нарисовать цифры "1.1." вручную, а в использовании встроенных стилей Word "Заголовок 1", "Заголовок 2" и так далее.

Проанализируем алгоритм вывода:

  1. Использование шаблона: Создадим пустой файл Word, настроим в нем многоуровневый список и свяжем его со стилями заголовков. Сохраним этот файл как макет в конфигурации 1С.
  2. Переключение стилей: При выводе каждой строки мы будем программно назначать ей соответствующий стиль Style.
  3. Обычный текст: После заголовка мы будем переключать стиль обратно на "Обычный" для вывода основного содержимого раздела.

Рассмотрим основной код формирования документа:


&НаКлиенте
Процедура ВставитьТегиДокумента(СтруктураWord, МассивСтрокСУровнями)
    Документ = СтруктураWord.COMСоединение.ActiveDocument;
    // Получаем объект выделения (курсор)
    Selection = Документ.Application.Selection;
    
    Для Каждого Строка ИЗ МассивСтрокСУровнями Цикл
        // Формируем название стиля в зависимости от уровня
        ИмяСтиля = "Заголовок " + Строка.УровеньЗаголовка;
        
        // Устанавливаем стиль для текущего абзаца
        Попытка
            Selection.Style = Документ.Styles(ИмяСтиля);
        Исключение
            // Если в шаблоне нет заголовка такой глубины, используем стандартный
            Selection.Style = Документ.Styles("Заголовок 1");
        КонецПопытки;
        
        // Пишем текст заголовка
        Selection.TypeText(Строка.СведенияПроекта);
        Selection.TypeParagraph(); // Переход на новую строку
        
        // Сбрасываем стиль на обычный для пояснительного текста
        Selection.Style = Документ.Styles("Обычный");
        
        Если ЗначениеЗаполнено(Строка.Пояснение) Тогда
            Selection.TypeText(Строка.Пояснение);
        Иначе
            Selection.TypeText("Содержание раздела уточняется.");
        КонецЕсли;
        
        Selection.TypeParagraph();
    КонецЦикла;
КонецПроцедуры

Важные уточнения и оптимизация

При работе с COM-объектами Word часто возникают проблемы с форматированием. Разберем несколько критически важных моментов, которые помогут сделать ваш код надежнее.

1. Объект Range вместо Selection. Использование Selection (выделения) визуально перемещает курсор по документу, что замедляет работу и может раздражать пользователя. Для профессиональной работы лучше использовать объект Range. Мы можем создавать новые параграфы и сразу присваивать им стили:


НовыйПараграф = Документ.Paragraphs.Add();
НовыйПараграф.Range.Text = "Текст заголовка";
НовыйПараграф.Range.Style = "Заголовок 2";

2. Свойство Style. Обратите внимание, что в некоторых версиях 1С или при копировании кода из интернета слово Style может отображаться с пробелом (St yle). Это ошибка форматирования форумов. Правильное написание свойства объекта — Style.

3. Предварительная очистка. Перед началом вывода полезно очистить документ от старого текста, если вы используете существующий макет:


Selection.WholeStory();
Selection.Delete();

4. Работа с Navigation Pane. Главное преимущество использования стилей Styles("Заголовок X") заключается в том, что Word автоматически выстраивает структуру документа. Пользователь сможет открыть панель навигации (Ctrl+F) и легко перемещаться по разделам, которые вы создали программно.

Заключение

Мы проанализировали ситуацию создания динамических списков и выяснили, что наиболее стабильный результат дает сочетание рекурсивной обработки данных в 1С и использование именованных стилей в шаблоне Word. Этот подход избавляет разработчика от необходимости вручную вычислять номера пунктов (1.2.3...), так как Microsoft Word берет эту задачу на себя при применении стилей заголовков. По аналогичному принципу подготовки данных работают и специализированные инструменты, такие как МС:Автопродажа для автоматического создания счетов и договоров в 1С.

Помните, что для корректной работы нумерации в самом шаблоне .dotx (или .docx) должен быть настроен "Многоуровневый список", где каждый уровень привязан к конкретному стилю заголовка. Тогда при программном назначении стиля "Заголовок 2" текст автоматически получит префикс 1.1., 1.2. и так далее.

← На главную