При разработке сложных печатных форм в 1С программисты часто сталкиваются с необходимостью вывода данных в форматы офисных документов, таких как Word. Использование объектов COM для взаимодействия с Microsoft Word (Новый COMОбъект("Word.Application")) является одним из наиболее прямолинейных подходов, однако он обладает существенным недостатком – низкой производительностью. Для форм с большим количеством страниц, параметров или изображений время формирования может достигать нескольких минут, что неприемлемо для пользователей, ожидающих быструю работу программы.
В этом руководстве мы рассмотрим различные подходы к созданию сложных печатных форм, уделяя особое внимание методам, которые позволяют значительно ускорить процесс и повысить гибкость разработки, предлагая альтернативы традиционному COM-подходу.
Это один из наиболее производительных и гибких способов создания документов Word из 1С. Он позволяет полностью избежать запуска приложения Microsoft Word, что критически важно для серверных решений и обеспечения высокой скорости работы.
word/document.xml.document.xml) с помощью объектов 1С для работы с XML (таких как ЧтениеXML, ПостроительDOM, ЗаписьDOM). На этом этапе происходит замена параметров, удаление ненужных элементов (например, закладок, строк таблиц), вставка изображений и другие манипуляции путем изменения узлов XML-дерева.COMОбъект("Word.Application"), так как не требуется запускать полноценное ресурсоемкое приложение Word. Сравнение показывает разницу от 10 минут до 10 секунд для сложной формы.Рассмотрим пошаговый пример реализации этого подхода в 1С:
// Шаг 1: Получаем двоичные данные макета Word
ДД = РеквизитФормыВЗначение("Объект").ПолучитьМакет(ИмяМакета);
// Шаг 2: Читаем двоичные данные в буфер и поток
Чтение = Новый ЧтениеДанных(ДД);
БуферДД = Чтение.ПрочитатьВБуферДвоичныхДанных();
Поток = Новый ПотокВПамяти(БуферДД);
// Шаг 3: Создаем временный каталог для распаковки
Каталог = КаталогВременныхФайлов() + "TempDocxProcessing";
СоздатьКаталог(Каталог);
// Шаг 4: Распаковываем ZIP-архив DOCX во временный каталог
ЗИП = Новый ЧтениеZipФайла(Поток);
ЗИП.ИзвлечьВсе(Каталог, РежимВосстановленияПутейФайловZIP.Восстанавливать);
ЗИП.Закрыть();
Поток.Закрыть();
Чтение.Закрыть();
// Шаг 5: Читаем основной XML-файл документа (word/document.xml)
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(Каталог + "\word\document.xml");
// Шаг 6: Строим DOM-дерево из XML для удобной навигации и модификации
Построитель = Новый ПостроительDOM;
Док = Построитель.Прочитать(ЧтениеXML);
ЧтениеXML.Закрыть();
// Шаг 7: Создаем разыменователь пространств имен для корректной работы с XPath
Разыменователь = Новый РазыменовательПространствИменDOM(Док);
// Шаг 8: Выполняем "магические заклинания" по замене параметров, удалению закладок и строк таблиц
// Здесь потребуется знание структуры WordprocessingML и использование XPath-выражений для поиска и модификации узлов.
// Например, для поиска текста:
// ВыражениеXPath = Док.СоздатьВыражениеXPath("//w:t[contains(text(), 'Параметр')]");
// Узлы = ВыражениеXPath.Вычислить(Док, Разыменователь);
// Для каждого УзелТекста Из Узлы Цикл
// УзелТекста.ТекстовоеСодержимое = СтрЗаменить(УзелТекста.ТекстовоеСодержимое, "Параметр", "НовоеЗначение");
// КонецЦикла;
// Пример удаления закладки по имени (сложнее, так как закладки - это пара тегов w:bookmarkStart и w:bookmarkEnd)
// w:bookmarkStart и w:bookmarkEnd обычно являются дочерними элементами w:p (параграфа)
// Допустим, нам нужно удалить параграф, содержащий закладку 'УдаляемаяЗакладка'.
// ВыражениеXPath = Док.СоздатьВыражениеXPath("//w:bookmarkStart[@w:name='УдаляемаяЗакладка']/..");
// УзелПараграфаСЗакладкой = ВыражениеXPath.Вычислить(Док, Разыменователь).Получить(0);
// Если УзелПараграфаСЗакладкой <> Неопределено Тогда
// УзелПараграфаСЗакладкой.Родитель.УдалитьДочерний(УзелПараграфаСЗакладкой);
// КонецЕсли;
// Шаг 9: Сохранение измененного DOM-дерева обратно в XML-файл
ЗаписьDOM = Новый ЗаписьDOM;
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(Каталог + "\word\document.xml");
ЗаписьDOM.Записать(Док, ЗаписьXML);
ЗаписьXML.Закрыть();
// Шаг 10: Повторная упаковка всех файлов во временном каталоге в новый ZIP-архив (DOCX)
Поток = Новый ПотокВПамяти();
ЗаписьZIP = Новый ЗаписьZipФайла(Поток,,,МетодСжатияZIP.Сжатие);
ЗаписьZIP.Добавить(Каталог + "\*.*", РежимСохраненияПутейZIP.СохранятьОтносительныеПути, РежимОбработкиПодкаталоговZIP.ОбрабатыватьРекурсивно);
ЗаписьZIP.Записать();
// Шаг 11: Получаем двоичные данные готового DOCX-файла
ДД = Поток.ЗакрытьИПолучитьДвоичныеДанные();
// Шаг 12: Помещаем двоичные данные во временное хранилище (или сохраняем на диск)
АдресВременногоХранилища = ПоместитьВоВременноеХранилище(ДД, УникальныйИдентификатор);
// Шаг 13: Очищаем временный каталог
УдалитьФайлы(Каталог);
Использование БСП: Важно отметить, что в типовых конфигурациях 1С, использующих Библиотеку Стандартных Подсистем (БСП), существуют встроенные механизмы, которые значительно упрощают этот процесс. Функции из общих модулей типа УправлениеПечатью или ШаблоныПечатиОфисныхДокументов могут предоставлять готовые решения для заполнения DOCX-шаблонов без COM-объектов, что сокращает объем ручной работы и повышает надежность.
Макеты в формате MXL являются нативным для 1С табличным документом, который во многом схож с электронной таблицей. Этот метод идеально подходит для создания большинства печатных форм в 1С.
Исторически одной из главных сложностей MXL была невозможность применить различное форматирование к отдельным словам или символам внутри одной ячейки (например, сделать одно слово жирным, а другое — курсивом). Форматирование всегда применялось ко всей ячейке целиком. Однако, начиная с платформы 1С:Предприятие версии 8.3.24, появилась возможность использовать объект ФорматированнаяСтрока в ячейках табличного документа, в том числе и в макетах. Это открывает новые горизонты для создания сложных печатных форм:
ФорматированнаяСтрока также поддерживает включение картинок и гиперссылок, что ещё больше расширяет её возможности.
// Создаем новый табличный документ
ТабДок = Новый ТабличныйДокумент;
// Создаем объект ФорматированнаяСтрока
ФорматированнаяСтрока = Новый ФорматированнаяСтрока;
// Добавляем текст с различным форматированием
// Первая часть - обычный текст
ФорматированнаяСтрока.Добавить("Это ");
// Вторая часть - жирный текст
ФорматированнаяСтрока.Добавить("очень важная", Новый ФорматТекста(Истина, Ложь, Ложь));
// Третья часть - курсив
ФорматированнаяСтрока.Добавить(" информация", Новый ФорматТекста(Ложь, Истина, Ложь));
// Четвертая часть - подчеркнутый текст
ФорматированнаяСтрока.Добавить(" для вас.", Новый ФорматТекста(Ложь, Ложь, Истина));
// Размещаем форматированную строку в ячейке табличного документа
Область = ТабДок.ПолучитьОбласть("R1C1");
Область.Текст = ФорматированнаяСтрока; // Теперь ячейка поддерживает сложное форматирование
ТабДок.Вывести(Область);
// Показываем табличный документ
ТабДок.Показать();
С помощью ФорматированнаяСтрока мы можем значительно улучшить внешний вид и читабельность MXL-форм, устраняя одно из давних ограничений табличного документа 1С.
Объект ФорматированныйДокумент (FormattedDocument) — это внутренний объект 1С, предназначенный для работы с текстами, имеющими сложное форматирование, подобно тому, как это делается в Word, но непосредственно внутри интерфейса 1С.
Сам объект ФорматированныйДокумент не сохраняется напрямую в файл в одном из стандартных офисных форматов. Однако его содержимое можно сохранить в ХранилищеЗначения для последующего восстановления или экспортировать в HTML/текстовый файл. Существуют подходы, позволяющие использовать HTML-представление ФорматированногоДокумента для последующей генерации Word-документа без COM-объектов, но это требует дополнительных шагов по конвертации.
Хотя этот метод признан самым медленным, в некоторых случаях он может быть единственно возможным, если требуется специфическая функциональность Microsoft Word, недоступная другими способами. Если вы вынуждены использовать COMОбъект("Word.Application"), мы можем предпринять шаги для минимальной оптимизации:
Visible объекта Word в Ложь (Word1C.Visible = Ложь;). Это не отменяет всех задержек, но визуально делает процесс менее "тяжелым" для пользователя.ActiveDocument: Если Word уже запущен или документ открыт, старайтесь работать с активным документом (Word1C.ActiveDocument) вместо того, чтобы каждый раз открывать новый, если это позволяет логика вашего решения.
// Пример использования COM-объекта с минимальной оптимизацией
Попытка
WordПриложение = Новый COMОбъект("Word.Application");
WordПриложение.Visible = Ложь; // Скрываем окно Word
ДокументWord = WordПриложение.Documents.Open("C:\Путь\К\Шаблону.docx");
// Замена параметров через закладки (Bookmarks)
Если ДокументWord.Bookmarks.Exists("НазваниеЗакладки") Тогда
ДокументWord.Bookmarks("НазваниеЗакладки").Range.Text = "Новое значение";
КонецЕсли;
// Замена параметров через поля документа (DocVariables)
// Необходимо, чтобы в шаблоне были созданы DocVariable
// Или используйте Find.Replace для поиска и замены текста
ДокументWord.Content.Find.Execute("<<Параметр1>>", Ложь, Ложь, Ложь, Ложь, Ложь, Истина, 1, Истина, "ЗначениеПараметра1", 2);
// ... другие операции с документом
ДокументWord.SaveAs("C:\Путь\К\ИтоговомуДокументу.docx");
ДокументWord.Close();
WordПриложение.Quit();
Исключение
Сообщить("Ошибка при работе с Word: " + ОписаниеОшибки());
Если WordПриложение <> Неопределено Тогда
WordПриложение.Quit();
КонецЕсли;
КонецПопытки;
Несмотря на эти оптимизации, основной минус — низкая скорость работы — остается, особенно при большом объеме данных или большом количестве заменяемых параметров, поскольку каждый вызов COM-метода требует взаимодействия с внешним приложением.
Выбор оптимального метода для разработки сложных печатных форм в 1С критически важен для производительности и удобства пользователей. Мы должны анализировать конкретные требования и доступные возможности платформы:
ФорматированнойСтроки (начиная с платформы 8.3.24) — это отличный выбор.ФорматированныйДокумент будет полезен.COMОбъект("Word.Application") оправдано только в тех случаях, когда необходима специфическая функциональность Microsoft Word, недоступная другими способами, и низкая скорость формирования не является критичной проблемой или может быть компенсирована небольшими оптимизациями.Всегда стоит начинать с анализа того, что именно является "сложным" в вашей печатной форме, и исходя из этого выбирать наиболее подходящий инструмент, который обеспечит как функциональность, так и приемлемую производительность.