Приветствую. Предлагаю вариант решения заполнения файла Word, без участия стороннего ПО, только нативные средства платформы 1С.
Известно, что файл *.docx упакованный контейнер с набором xml и медиа файлов. Но об *.doc такого сказать нельзя, это скорее бинарник. Файл docx легко распаковывается архиватором, а doc нет. А раз распаковывается и внутри у него знакомые xml, то почему бы не попробовать изменить xml программно? Необходимые средства для выполнения этой задачи платформа имеет.
Сначала попробуем разобраться как же устроен docx изнутри. Создадим новый файл Word с текстом - "Просто текст, а это МойПараметр". Затем распакуем файл и увидим следующую иерархию данных.
О назначении каждого из файлов хорошо написано тут. Из всех файлов для решения нашей задачи интересен только один. Адрес файла - word/document.xml. Открываем файл и видим, что содержимое не отформатировано и для визуального анализа не подойдет. Отформатировать xml онлайн можно тут или же использовать Notepad++. Дальше по ключевому слову МойПараметр находим параметр и видим примерно следующее.
<w:r>
<w:rPr>
<w:lang w:val="ru-RU"/>
</w:rPr>
<w:t>Просто текст</w:t>
</w:r>
<w:r w:rsidR="004E0307">
<w:rPr>
<w:lang w:val="ru-RU"/>
</w:rPr>
<w:t>, а это МойПараметр</w:t>
</w:r>
После небольшого анализа понятно, что текст находится в тегах t с префиксом w (стоит сказать, что все теги файла имеют этот префикс. Это пространство имен http://schemas.openxmlformats.org/wordprocessingml/2006/main). Для упрощения задачи, будем считать, что параметры шаблона всегда будем писать "верблюжьей" нотацией, потому как, если например написать вот так [Параметр1], то в xml это будет три тега <w:t>, с разными родительскими тегами <w:r>, что существенно усложнит алгоритм замены. Таким образом, чтобы программно заменить параметр на нужный текст, нужно найти тег <w:t> с текстом параметра и выполнить замену. Потом файл с замененными параметрами сохранить и упаковать в архив.
Для примера возьмем абстрактный шаблон. Добавим в него текст, параметры (помним о "верблюжьей" нотации), а также какое-либо изображение, таблицу и прочее - чтобы убедиться, что после заполнения документ будет корректно отображать содержимое.
Создадим обработку, у которой в макет с типом ДвоичныеДанные положим наш подопытный файл docx. Дальше создадим форму, команду формы и для команды элемент управления. По нажатию на кнопку передадим управление на сервер и начнем писать код. Для начала получим шаблон из макета обработки.
BinaryData = FormAttributeToValue("Object").GetTemplate("Template");
Так как тип макета ДвоичныеДанные, то и получим также двоичные данные. Дальше нужно полученные данные распаковать. Для этого воспользуемся объектом ЧтениеZipФайла. Объект инициализируется на основании объекта ПотокВПамяти, а поток в памяти создается на основании объекта БуферДвоичныхДанных, который получается из метода ПрочитатьВБуферДвоичныхДанных объекта ЧтениеДанных, который создается на основании двоичных данных, которые у нас есть.
Reader = New DataReader(BinaryData);
BinaryDataBuffer = Reader.ReadIntoBinaryDataBuffer();
Stream = New MemoryStream(BinaryDataBuffer);
ZipReader = New ZipFileReader(Stream);
ZipReader.ExtractAll(Dir);
ZipReader.Close();
Stream.Close();
Reader.Close();
Теперь прочитаем document.xml. Прочитать можно разными способами, но мы воспользуемся ПостроительDOM, который вернет объект ДокументDOM.
XMLReader = New XMLReader;
XMLReader.OpenFile(PathXMLFile);
Builder = New DOMBuilder;
DomDocument = Builder.Read(XMLReader);
XMLReader.Close();
Теперь самое интересное - поиск тегов <w:t>. Можно это сделать разными способами, вплоть до обхода ДокументDOM как дерева. Но существует способ проще. Поскольку тегов <w:t> может быть достаточно много, а нужны только те, в которых указаны наши параметры, то воспользуемся методом СоздатьВыражениеXPath объекта ДокументDOM (XPath по сути язык запросов к файлам xml).
Resolver = New DOMNamespaceResolver(DomDocument);
For Each MapElement In FillData Do
XPathExpression = DomDocument.CreateXPathExpression("//w:t[contains(text(),'"+MapElement.Key+"')]", Resolver);
XPathResult = XPathExpression.Evaluate(DomDocument);
Node = XPathResult.IterateNext();
While Node <> Undefined Do
Node.TextContent = StrReplace(Node.TextContent, MapElement.Key, MapElement.Value);
Node = XPathResult.IterateNext();
EndDo;
EndDo;
Поясню приведенный сниппет. Сначала создаем РазыменовательПространствИменDOM (подробнее тут). Дальше обходим некую коллекцию данных, ключ которой это имя параметра, который подлежит замене, а значение - то, что должно быть вместо параметра. В метод СоздатьВыражениеXPath передаем запрос к xml, которым выберем все теги <w:t> файла на всех уровнях, текст которых содержит наш параметр. Вычисляем результат и обходим его, заменяя параметры нужными значениями.
Теперь сохраним ДокументDOM. Для этого используем объект ЗаписьDOM.
DOMWriter = New DOMWriter;
XMLWriter = New XMLWriter;
XMLWriter.OpenFile(PathXMLFile);
DOMWriter.Write(DomDocument, XMLWriter);
XMLWriter.Close();
Осталось создать такой же контейнер, который мы распаковывали. Используем для этого ЗаписьZipФайла и уже знакомый объект ПотокВПамяти. Иерархия файлов в контейнере должна быть такой же, как и до распаковки. Для этого в метод Добавить объекта ЗаписьZipФайла передадим РежимСохраненияПутейZIP.СохранятьОтносительныеПути.
Stream = New MemoryStream;
ZipWriter = New ZipFileWriter(Stream,,,ZIPCompressionMethod.Deflate);
ZipWriter.Add(TempDir+"\*.*", ZIPStorePathMode.StoreRelativePath, ZIPSubDirProcessingMode.ProcessRecursively);
ZipWriter.Write();
BinaryData = Stream.CloseAndGetBinaryData();
Теперь у нас есть двоичные данные, которые передаем клиентской процедуре, там их записываем в файл и открываем приложением по умолчанию для docx.
Скриншот полученной обработки
Результат работы заполнения документа Word. Шаблон до заполнения
Шаблон после заполнения
Работы проводились с Word 2010, но думаю, что на других версиях также должно работать.
Требования к платформе: версия 8.3.9+, так как только в этой версии появилась возможность работы с потоками. Но эту проблему легко обойти, если использовать старый добрый ввод вывод через временные файлы.
Решение кроссплатформенное. В приложенных файлах обработка, код которой на 90% приведен в публикации.