Привет, Хабр! Меня зовут Дарья Чувашова, я — руководитель группы отделения SAP-разработки. В процессе моей проектной деятельности мне приходилось сталкиваться с задачами выгрузки документов в .doc формат и делать это нужно было быстро. При этом эти документы могли быть с совершенно разным форматированием, кучей таблиц, реквизитов и т. д. В SAP для выгрузки в форматы pdf и excel есть удобные инструменты, возможность работать с формулярами и графическими редакторами форм. Для работы с форматом.doc инструментов меньше. В этой статье я расскажу о быстром и самом простом способе выгрузить документ любой сложности.
![](https://habrastorage.org/getpro/habr/upload_files/c4b/228/1ca/c4b2281ca51b7c8381fe7b7e454ba63c.jpg)
Почему я решила написать этот «how‑to»? Как я упомянула, задачи по выгрузке файлов в.doc мне приходилось выполнять часто. В какой‑то момент я собрала все лайфхаки и советы по ускорению работы в один материал, а сейчас хочу поделиться им с хабровской аудиторией. Надеюсь, для коллег записи будут полезными. Описанный вариант решения имеет свои особенности, поэтому я постараюсь на примерах продемонстрировать некоторые «узкие» моменты.
Пошаговая инструкция решения вопроса
Шаг 1
В первую очередь нам нужно подготовить шаблон в MS Word в нужном формате. Важно заполнить все реквизиты тестовыми данными для примера, это значительно упростит нам жизнь в последующих действиях.
В качестве примера рассмотрим вот такой документ «Счёт‑фактура» в MS Word:
![Этот и другие используемые здесь примеры были взяты из открытого источника: https://glavkniga.ru/situations/k505106 Этот и другие используемые здесь примеры были взяты из открытого источника: https://glavkniga.ru/situations/k505106](https://habrastorage.org/getpro/habr/upload_files/e71/4e4/b39/e714e4b394efb59a77c6ce03f24aa805.png)
Шаблон необходимо заполнить тестовыми примерами, чтобы проверить, что при заполнении ничего не съезжает, и все реквизиты остаются на месте:
![](https://habrastorage.org/getpro/habr/upload_files/2cc/dc3/a95/2ccdc3a9546b54f1763732573af962ec.png)
Шаг 2
Сохраним наш документ в формате XML: Файл - Сохранить как. Выбираем расширение .xml
![](https://habrastorage.org/getpro/habr/upload_files/080/ff1/c04/080ff1c0430c8ece0ea6ea45769e94f3.png)
![](https://habrastorage.org/getpro/habr/upload_files/9a6/780/d90/9a6780d9050020e0a3d3b7c41deb1b32.png)
Примечание: для большинства задач вполне достаточно формата.doc, он поддерживает ограничения редактирования, элементы управления и т. п.
Для того чтобы открыть данный файл, мне удобно использовать программу Altova XML Spy. Скорее всего нам потребуется проанализировать содержимое, а в данной программе выполнять анализ файла очень удобно за счёт подсветки синтаксиса. Вы, конечно, можете использовать любой другой редактор.
Открываем свой XML, видим примерно такую картину:
![](https://habrastorage.org/getpro/habr/upload_files/b75/c76/0e6/b75c760e62e9db8ae36b205885bf1d1f.png)
После применения команды PrettyPrinter:
![](https://habrastorage.org/getpro/habr/upload_files/71f/13d/a25/71f13da25195f8a0b3b1ff73518c2ef4.png)
Шаг 3
Переходим в SAP. В своём пакете разработки создадим Преобразование:
![](https://habrastorage.org/getpro/habr/upload_files/906/601/56c/90660156cc79aea2498d3ad9156a6de8.png)
Выберем трансформацию XSLT:
![](https://habrastorage.org/getpro/habr/upload_files/25d/fc9/b20/25dfc9b20be427f8e0db6a24b7b1dd4b.png)
Видим следующую картину:
![](https://habrastorage.org/getpro/habr/upload_files/2d5/0bc/e9a/2d50bce9af0304210727e798bab1f0ae.png)
Для того, чтобы наша трансформация верно работала, необходимо указать следующий код между тегами <xsl:template match="/"> </xsl:template>:
<xsl:processing-instruction name="mso-application" progid="Word.Document">
<xsl:text progid="Word.Document"/>
</xsl:processing-instruction>
![](https://habrastorage.org/getpro/habr/upload_files/747/b05/9e8/747b059e80758f5ee8c7d818c2f60353.png)
Теперь можно смело вставить весь XML‑код ниже из нашего документа:
![](https://habrastorage.org/getpro/habr/upload_files/da3/e68/d7e/da3e68d7e33cefd499ac8b87a17c302b.png)
Визуально просматриваю данный XML‑код, обнаруживаю, что часть тегов подсвечивается, как текст:
![](https://habrastorage.org/getpro/habr/upload_files/f86/4d9/50a/f864d950a0d5f0bac375b8ad4330bc09.png)
Вижу, что это произошло из‑за кавычек в наименовании компании (Company), смело их удаляю:
![](https://habrastorage.org/getpro/habr/upload_files/fa2/2e4/e2d/fa22e4e2d5a498eefb4422edb5efb193.png)
Теперь пытаемся активировать трансформацию. В 90% случаях активация пройдёт успешно.
Но если у вас появятся подобные ошибки,
![](https://habrastorage.org/getpro/habr/upload_files/237/f6a/83b/237f6a83b5605037a92bed708c005cab.png)
Предлагаю стереть данные коды, так как они не имеют никакого смысла для генерации документа из SAP.
![](https://habrastorage.org/getpro/habr/upload_files/d44/4fe/abb/d444feabb2eaf7c2e6ed5db223469b38.png)
Удаляем:
![](https://habrastorage.org/getpro/habr/upload_files/ff5/d4d/dbb/ff5d4ddbb2a38c85aa304761e00ad7c6.png)
После удаления всех кодов трансформация успешно активируется.
Шаг 4
Переходим в программу. Для вызова трансформации и выгрузки файла привожу для примера такой код:
![](https://habrastorage.org/getpro/habr/upload_files/655/95d/5b4/65595d5b498963ba9661d85ab629f407.png)
Данный код максимально облегчён для простоты восприятия и предельной наглядности.
После запуска программы в папке C:\TEMP сохранится файл точно в таком же виде, как наш подготовленный шаблон:
![](https://habrastorage.org/getpro/habr/upload_files/f40/f1a/8e8/f40f1a8e87503c530c52c649f4b3a716.png)
При открытии файла может возникнуть следующая ошибка:
![](https://habrastorage.org/getpro/habr/upload_files/0aa/1a0/ee0/0aa1a0ee0cb40828e453d6448de1492e.png)
Для того, чтобы от неё избавиться, переходим в трансформацию и ищем /word/settings.xml
![](https://habrastorage.org/getpro/habr/upload_files/f8e/815/563/f8e815563d5b9f111229b2a04dc0d333.png)
Избавиться от ошибки мне помогло удаление всего блока <pkg:part … </pkg:part>. Это не повлияло на работоспособность, и файл стал открываться нормально. Без подсветки синтаксиса тяжело искать закрывающий тег, поэтому имеет смысл снова воспользоваться программой Altova XML Spy (в данной программе вы можете удалить лишний код, а затем вставить новую версию в нашу трансформацию).
![](https://habrastorage.org/getpro/habr/upload_files/028/d1d/65c/028d1d65c0fd3d4cfb0c81a304e6fb67.png)
Удаляем и активируем, проверяем, что ошибка ушла и с файлом всё в порядке.
![](https://habrastorage.org/getpro/habr/upload_files/724/19c/07f/72419c07f010624fe6274788b7c08361.png)
Шаг 5
Переходим к выгрузке данных из контекста. Начнём с самого простого: выгрузим данные в поле «Продавец»:
![](https://habrastorage.org/getpro/habr/upload_files/618/9fc/d7a/6189fcd7a6dbebcc58e6283821a64106.png)
Контекст представляет собой структуру c данными, например, вот такую:
![](https://habrastorage.org/getpro/habr/upload_files/867/9aa/629/8679aa629c30a8fbecf5ce8d7aa89ce4.png)
Её мы заполняем и подаём в трансформацию как контекст. Далее копируем из файла, заполненного в качестве примера, текст из реквизита «Продавец» и ищем это место в нашей XML:
![](https://habrastorage.org/getpro/habr/upload_files/fa2/b66/a28/fa2b66a2870f06158e1862f04529305e.png)
Вместо данного текста вставляем:
![](https://habrastorage.org/getpro/habr/upload_files/4a2/b68/495/4a2b68495dedc15afc8d1fa7a596f11e.png)
Не забываем указать нужную структуру контекста и сделать выборку данных. Для примера прописываю хардкодом наименование продавца:
![](https://habrastorage.org/getpro/habr/upload_files/e3d/160/82e/e3d16082e68d894b8f4a5f8cdf3d46d9.png)
Результат трансформации:
![](https://habrastorage.org/getpro/habr/upload_files/132/8aa/2a8/1328aa2a8360dd3eda55dff4abda1f6e.png)
Остальные реквизиты заполняем аналогично.
Как видим, заполненный на Шаге 1 пример нам помогает выполнять быструю навигацию по XML и искать нужные места для доработки.
Отдельную сложность может представлять собой заполнение табличных данных. В структуре контекста имеем вложенную таблицу с данными T_INVOICE. Для вывода данных используем цикл for each. Начнём с 1 строки 1 столбца. Ищем поиском пример «Яблоки» и вставляем код, приведённый чуть ниже.
Теги описания таблицы довольно понятны: <w:tc> </w:tc> — стоблец, <w:tr </w:tr> — соответственно строка, ну и сам текст <w:t> </w:t>.
Если мы хотим каждую строку таблицы из контекста выводить в новую строку таблицы, то цикл ставим перед тегом строки и закрываем после окончания описания строки:
![](https://habrastorage.org/getpro/habr/upload_files/a8f/fdf/979/a8ffdf979ed39c24f8113bfa2b7b85ad.png)
Конец цикла будет обозначен тут:
![](https://habrastorage.org/getpro/habr/upload_files/d24/f6c/ac0/d24f6cac032d628c354bbcab1e4029ef.png)
Так как таблица большая, окончание цикла будет через 400 строк, поэтому удобно воспользоваться опять же программой с подсветкой тегов, таким образом выводим все необходимые элементы таблицы.
Результат:
![](https://habrastorage.org/getpro/habr/upload_files/3ca/260/143/3ca260143767d45b9d891fc8835d5984.png)
Видим, что строка автоматически добавилась. Так как нам не нужны старые данные из примера, удалим эти строки из таблицы. Ищем так же по тегам.
![](https://habrastorage.org/getpro/habr/upload_files/3f6/85c/809/3f685c80947c90feee0d870a35b6fdd1.png)
В идеале можно было бы в самом шаблоне оставить лишь одну строку для заполнения, тогда лишних действий по удалению колонок не пришлось бы делать. Но я хочу показать неидеальный случай.
Если необходимо вывести данные из таблицы контекста не в каждой строке таблицы, а текстом с переносом, то можем воспользоваться тегом переноса строки <w:br/>, например,
![](https://habrastorage.org/getpro/habr/upload_files/2df/f40/2a0/2dff402a05ac9744d388d31914ca6b3a.png)
Получим вот такой результат:
![](https://habrastorage.org/getpro/habr/upload_files/573/8fc/adb/5738fcadb373bc1b41db9975fef734de.png)
Ещё немного полезных рекомендаций
Мы разобрали основные шаги, как сделать выгрузку любого реквизита и заполнить таблицу. При этом необязательно думать о размере шрифта или форматировании, достаточно изначально выстроить необходимые настройки и правки в исходном документе.
Что ещё записано в моих заметках?
Как поменять шрифт быстро, если он перестал подходить? Допустим, мы желаем заменить Arial на Calibri. Для этого в трансформации выполняем поиск Arial — «Заменить все» и вставляем название нового шрифта Calibri.
Как сделать защиту листа и позволить редактировать лишь некоторые реквизиты в выгруженном файле?
Для этого нужно в исходном файле на 1 шаге настроить защиту листа, тогда кодирующие эту операцию теги будут отражены в нашей трансформации.
Примеры исходного кода из статьи можно увидеть в репозитории github.
Данной информации должно быть достаточно, чтобы сделать выгрузку практически любого документа быстро и эффективно.
Комментарии (6)
PhysicalGraffiti
00.00.0000 00:00+3В первую очередь нам нужно вспомнить, что.doc формат — это по сути тот же самый XML формат.
Это не так.
В статье идет работа с docx - это zip архив, который содержит несколько файлов и папок (https://ru.wikipedia.org/wiki/Office_Open_XML).
doc - проприетарный бинарный формат (https://en.wikipedia.org/wiki/Doc_(computing)#Microsoft_Word_Binary_File_Format)DChuvashova Автор
00.00.0000 00:00+1Спасибо за комментарий)
Мой первый блин немного комом, как говорится, буду внимательней в будущем :)
ibnteo
00.00.0000 00:00Давно ещё сделал XSLT трансформер из формата AbiWord в FB2, можно быстро создать книгу из документа, которую удобно читать на небольших экранах.
mthps
"За 5 простых шагов"
"Шаг 0"
(10 экранов текста)
"Шаг 6"
Почему в сапе всегда так?
DChuvashova Автор
0 шаг можно поручить консультанту или тому, кто лучше всех знает ворд)