Часто возникает задача: автоматически сформировать документ Word по шаблону, но не просто вставить одиночные значения, а заполнить целую таблицу, количество строк в которой заранее неизвестно. Например, выгрузить список товаров, сотрудников или номенклатуры из табличной части внутреннего документа 1С. Стандартный механизм заполнения по закладкам здесь не поможет, так как он не умеет динамически добавлять строки.
Давайте вместе разберемся, как решить эту задачу. Проанализируем несколько подходов, от доработки типового функционала до использования внешних компонент, и подробно рассмотрим их реализацию.
Этот способ является наиболее производительным и не требует установки Microsoft Word на сервере 1С. Идея заключается в том, чтобы "обмануть" систему автозаполнения, подставив ей готовый XML-фрагмент, описывающий таблицу Word. Разберем по шагам, как это сделать.
Изучаем структуру файла DOCX.
Для начала выясним причину, почему этот метод работает. Файл формата .docx — это на самом деле ZIP-архив. Если изменить его расширение на .zip и распаковать, внутри мы найдем несколько папок и XML-файлов. Основное содержимое документа хранится в файле word/document.xml.
Проведем небольшой эксперимент: создайте в Word пустой документ, добавьте в него простую таблицу с парой строк и столбцов, отформатируйте ее как нужно (шрифты, границы, ширина колонок) и сохраните. Затем, как описано выше, изучите его внутренний document.xml. Вы увидите, что таблица описывается тегами: <w:tbl> (сама таблица), <w:tr> (строка таблицы), <w:tc> (ячейка), <w:p> (параграф внутри ячейки) и <w:t> (текст). Поняв эту структуру, мы сможем сформировать аналогичный XML-код средствами 1С.
Готовим данные и XML в 1С.
В настройках автозаполнения шаблона нам нужно будет использовать скрипт на встроенном языке. Этот скрипт должен собрать данные из табличной части документа-основания (например, в ТаблицуЗначений), а затем на основе этих данных сформировать одну большую строку, содержащую полный XML-код для таблицы Word. Для удобства можно создать отдельную экспортную функцию в общем модуле, которая будет принимать на вход таблицу значений и возвращать готовую XML-строку.
Вносим изменения в общие модули 1С:Документооборот.
Теперь самое главное. Стандартный механизм при вставке текста в шаблон экранирует спецсимволы (например, < и >), чтобы они отображались как текст, а не как теги. Нам нужно это поведение обойти. Для этого потребуется внести небольшие изменения в конфигурацию. Важно: все доработки выполняйте через расширения, чтобы не снимать конфигурацию с поддержки.
Нам нужно модифицировать процедуру ЗаписатьВXMLСодержимое в общем модуле АвтозаполнениеШаблоновФайловКлиентСервер. Добавим условие, которое будет проверять, содержит ли наша строка тег таблицы <w:tbl>. Если да, то вставлять эту строку в XML-документ "как есть", без обработки.
Посмотрим на пример измененной процедуры:
Процедура ЗаписатьВXMLСодержимое(ЗаписьXML, Знач Содержимое)
Спецсимволы = Новый Соответствие;
Спецсимволы.Вставить("<w:br/>", Символы.ПС);
Спецсимволы.Вставить("</w:t><w:tab/><w:t>", Символы.Таб);
Для Каждого Спецсимвол Из Спецсимволы Цикл
Содержимое = СтрЗаменить(Содержимое, Спецсимвол.Значение, СтрШаблон("_###_%1_###_", Спецсимвол.Ключ));
КонецЦикла;
МассивПодстрок = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(Содержимое, "_###_", Ложь);
Для Каждого Подстрока Из МассивПодстрок Цикл
Если Спецсимволы[Подстрока] <> Неопределено Тогда
ЗаписьXML.ЗаписатьБезОбработки(Подстрока);
// Начало доработки
ИначеЕсли СтрНайти(Содержимое, "<w:tbl>") > 0 Тогда
ЗаписьXML.ЗаписатьБезОбработки(Подстрока);
// Конец доработки
Иначе
ЗаписьXML.ЗаписатьТекст(Подстрока);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Ключевое изменение — это блок ИначеЕсли. Он проверяет наличие тега таблицы и использует метод ЗаписьXML.ЗаписатьБезОбработки(), который вставляет строку в итоговый XML без изменений. Также может потребоваться аналогичная доработка в общем модуле АвтозаполнениеШаблоновФайловСервер.
Настраиваем шаблон.
В самом шаблоне Word .docx в нужном месте создайте закладку (например, "ТаблицаНоменклатуры"). В настройках автозаполнения в 1С:ДО укажите, что эту закладку нужно заполнять результатом выполнения вашего скрипта, который возвращает XML-строку.
Итог по решению: этот метод элегантен и быстр, но требует аккуратной доработки конфигурации и хорошего понимания XML-структуры документов Word.
Это более традиционный и гибкий подход, который позволяет управлять документом Word практически без ограничений. Однако у него есть важное требование: на машине, где будет выполняться код (сервер 1С или клиентский компьютер), должен быть установлен Microsoft Word.
Рассмотрим подробнее, как работать с этим методом.
Подготовка шаблона.
В шаблоне .docx можно поступить двумя способами. Первый — создать закладку в том месте, куда нужно вставить таблицу. Второй, более предпочтительный — создать "таблицу-шаблон". Она должна содержать "шапку" и одну пустую, но полностью отформатированную строку для данных. Эту строку мы будем программно копировать столько раз, сколько нам нужно.
Написание кода на 1С с использованием COM.
В коде 1С (например, в обработке или общем модуле) мы будем создавать COM-объект Word и манипулировать им.
Посмотрим на примерный алгоритм действий:
// Код выполняется на стороне, где установлен MS Word (клиент или сервер)
Попытка
WordApp = Новый COMОбъект("Word.Application");
Исключение
Сообщить("Не удалось запустить Microsoft Word! " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// Открываем документ по шаблону
WordDoc = WordApp.Documents.Add(ИмяФайлаШаблона);
// Получаем данные из 1С, например, в ТаблицуЗначений
ДанныеДляТаблицы = ПолучитьДанныеИзТЧ();
// Находим нашу таблицу в документе (например, она первая по счету)
ТаблицаWord = WordDoc.Tables(1);
// Получаем ссылку на последнюю строку (наш "шаблон строки")
СтрокаШаблон = ТаблицаWord.Rows(ТаблицаWord.Rows.Count);
// В цикле обходим данные и добавляем строки в Word
Для Каждого СтрокаДанных Из ДанныеДляТаблицы Цикл
// Копируем форматированную строку-шаблон
НоваяСтрока = ТаблицаWord.Rows.Add(СтрокаШаблон);
// Заполняем ячейки новой строки
НоваяСтрока.Cells(1).Range.Text = СтрокаДанных.Номенклатура;
НоваяСтрока.Cells(2).Range.Text = СтрокаДанных.Количество;
НоваяСтрока.Cells(3).Range.Text = СтрокаДанных.Цена;
КонецЦикла;
// После цикла можно удалить исходную строку-шаблон, если она была пустой
СтрокаШаблон.Delete();
// Делаем Word видимым для пользователя и сохраняем результат
WordApp.Visible = Истина;
// WordDoc.SaveAs(ИмяНовогоФайла);
// WordApp.Quit();
Интеграция с 1С:Документооборот.
Этот код можно обернуть в процедуру и вызывать ее, например, по кнопке из формы документа или в рамках бизнес-процесса. Интегрировать его напрямую в механизм автозаполнения сложнее, так как он рассчитан на возврат простых значений, а не на выполнение таких сложных манипуляций с файлами.
Итог по решению: COM-объект дает полный контроль над документом, позволяя создавать сложные структуры, но привязывает нас к наличию установленного MS Word и может работать медленнее на больших объемах данных по сравнению с прямым формированием XML.
Проблема ручных правок: Как было справедливо отмечено, любой механизм автоматического заполнения имеет недостаток. Если пользователь откроет сгенерированный файл, внесет в таблицу ручные правки, а затем запустит процедуру заполнения заново, его изменения будут потеряны. Код просто пересоздаст таблицу на основе актуальных данных из 1С. Это важно донести до конечных пользователей.
Выбор решения: Если у вас нет возможности или желания дорабатывать конфигурацию, а на сервере или клиентских машинах установлен Word, то метод с COM-объектом будет проще в реализации. Если же для вас критична производительность и независимость от установленного ПО, то стоит потратить время на изучение и реализацию метода с прямым формированием XML.
← К списку