Что значит генерация документов

Генерация документов — взгляд изнутри

Создание модуля генерации документов только на первый взгляд может показаться делом простым. На самом деле, чтобы создать такой модуль, надо решить несколько проблем, без решения которых его реализация будет неполноценной. Функционал генератора документов должен уметь решать проблемы, идущие в виде требований из реальной жизни. Рассмотрим одну из множества проблем.

Требованиe: пользователи\бизнес желают иметь библиотеку пунктов (параграфов), которые вставляются в документы, генерируемые по различным шаблонам. Изменение пункта в библиотеке должно приводить к изменению этого пункта в документах, которые генерируются по этим шаблонам. Изменять пункты хотел бы сам бизнес, без участия ИТ. Составление шаблонов (по которым генерируются документы) с учетом вставки в разные их места пунктов из библиотеки сокращает размер шаблонов, они становятся полиморфными, и, соответственно, уменьшается количество шаблонов и упрощается их сопровождение.

Начальные данные: для удобства работы с пунктами библиотека может состоять, например, из фрагментов документа, создаваемых в MS Word. Т.е. их создание и редактирование производится в MS Word. Библиотечные пункты хранятся, например, в базе данных и\или в файловой папке. Какие конкретно пункты будут вставлены в документ при генерации определяется во время исполнения приложения, которое использует модуль генератора.

Читайте также:  Непременно это что значит выражение

Первая задача, которую надо решить, это задача сопряжения отступов текста, указанных в шаблоне, и добавляемых пунктов из библиотеки, сопряжение размеров шрифта и т.п. Данная задача частично решается правилами составления пунктов, выбранным заранее шрифтом и его размером. Отступы же генератор должен определить сам, исходя из контекста того места в шаблоне, куда вставляется пункт. К счастью, такой контекст определить не сложно, поэтому эта задача здесь просто обозначена.

Вторая задача более сложная. Рассмотрим пример пункта и на его основе перечислим проблемы:

[1.2] Библиотечный пункт является примером, составленным г-ном [Ивановым] для демонстрации проблем, описанных в пунктах [2.3] и [3.1] [«Краткого описания»][данного изложения]

В приведенном примере фрагменты текста, помещенные в [. ] скобки, должны задаваться параметрически. Т.е. данный библиотечный пункт при вставке в реальный документ мог бы выглядеть так:

3.1 Библиотечный пункт является примером, составленным г-ном Горбунковым С.С. для демонстрации проблем, описанных в пунктах 4.1 и 4.6 «Краткого описания»

Если приложение в момент исполнения может знать о Горбункове С.С. и о том, описание это или изложение, то о том, какой именно номер пункта в шаблоне, 1.2 или 3.1, приложение не знает, да и не должно. Библиотечных пунктов может быть несколько, вставляться они могут в разные места разных шаблонов, нумерация разделов в них не совпадает, да и ссылаться пункты могут на другие пункты, номера которых не должны быть известны приложению. Приложение должно поручить задачи расчета номеров пунктов самому генератору. Шаблоны совместно с генератором должны обеспечивать нумерацию своих и библиотечных пунктов сами, впрочем, как и определение номеров ссылок на пункты.

Например, в одном шаблоне конкретный библиотечный пункт может ссылаться на пункты 4.1 и 4.6, в другом (или в этом же самом) только на пункт 2.5.1. Кроме того, если нумерация пунктов выполняется внутри одного документа, то ссылки могут ссылаться на пункты в другом документе, как, например, «Краткое описание» может быть не генерируемым в данный момент документом, а уже существующим. Все это говорит о том, что библиотечный пункт должен быть параметризован. Если генератор не может выполнять такие операции, то вносить правки в документ придется человеку вручную, а человек может ошибаться.

Например, вид разметки библиотечного пункта может быть такой:

[Счетчик:X] Библиотечный пункт является примером, составленным г-ном [Наименование автора] для демонстрации проблем, описанных в пунктах [Глобальная ссылка:A][ и [Глобальная ссылка:B]] [[Альтернатива:1=»Краткого описания»]|[Альтернатива:2=данного изложения]]

Итак, если модуль генератора знает, каково значение счетчика:X до вставки библиотечного пункта, знает значение поля [Наименование автора], имеет информацию о документе «Краткое описание» и может найти в нем конкретные значения глобальных счетчиков (доступных из других документов) с именами A и B этого документа, и если он знает альернативу 1 или 2, то окончательное значение библиотечного пункта вычисляется генератором по входным параметрам и данный пункт можно использовать в разных шаблонах без проблем.

Остается только добавить, что модифицировать такой библиотечный пункт в MS Word могут не только сотрудники ИТ, но и обученные сотрудники подразделений организаций. Что радует.

Источник

Автоматическая генерация технической документации

Продолжая тему использования Asciidoc (и других аналогичных форматов) для организации процессов непрерывного документирования, хочу рассмотреть тему автоматический генерации технической документации.

Автоматическая генерация документации — распространенный, но очень расплывчатый термин. Я понимаю под этим термином извлечение для представления в удобном виде информации, содержащейся в исходном коде и настройках документируемой программы (информационной системы).

Общая схема автоматической генерации документации

Если рассматривать процесс автоматической генерации как чёрный ящик, то на входе имеем исходный код, а на выходе — документацию или её фрагмент. Однако в реальности при автоматической генерации документации целесообразны еще два промежуточных звена.

  • преобразование исходного кода в структурированный формат. Шаг обусловлен тем, что для получения документов используются шаблонизаторы. Все современные технологии, связанные с генерацией человеко-читаемых документов, пользовательских интерфейсов, программного кода, активно используют шаблонизаторы, подключаемые в виде библиотек или реализованные внутри программного кода. Вход для шаблонизатора — структура данных, которую легко получить из файлов в форматах JSON/YAML или XML;
  • преобразование структурированного формата в один из форматов документации (обычно Asciidoc, DITA, Docbook, Markdown, reStructuredText).

За исключением самых простых случаев, документация готовится в различных выходных форматах (html, docx, odt, pdf и т.п.) и собирается из разных источников (в том числе не автоматически генерируемых) поэтому целесообразно использовать специальные форматы для подготовки документации. Предположим, необходимо подготовить документацию по стандартам ЕСКД? Эта проблема, описана в предыдущей статье. При решении проблем автоматической генерации хватает проблем и без требований ГОСТ.

Общая схема генерации документации выглядит следующим образом:

Рассмотрим практические приёмы, которые можно использовать при реализации ИТ-проектов. Для примеров будем использовать Asciidoc, однако приёмы применимы к любым языкам разметки текста(reStructuredText, Markdown), и текстовым маркапам для построения диаграмм (рекомендую проект kroki, который позволяет быстро ознакомиться и внедрить наиболее популярные средства построения диаграмм).

Преобразование исходного кода в структурированный формат

Единых подходов к превращению исходного кода в структурированный формат не существует. Рассмотрим наиболее частые варианты.

Информация для документации извлекается из структуры исходного кода

Как правило, используются дополнительные средства языка, обычно комментарии в специальном формате (комментарии Javadoc, ReST и т.п.) и аннотации.

Средств, обеспечивающих преобразование исходного кода в документацию, причём очень зрелых, много. Можно смело брать и использовать подходящие для конкретного проекта. Разработка собственных средств затратна. Мы пошли указанным путём только раз, разрабатывая проект для миграции структуры базы данных. Целесообразность определялась использованием средства во всех наших проектах и желанием попробовать свои силы.

Следующие подходы более гибки с точки зрения настройки автоматической генерации документации в реализуемых проектах.

Структурированный формат получается как один из результатов исполнения исходного кода

При данном подходе считывается и сохраняется в структурированный формат состояния объектов (например, структуры базы данных, конфигурации развернутой среды информационной системы и т.п.), создаваемых в результате работы приложения.

Отдельно отметим использование для документирвоания логов. Типовой пример — тесты. Например, большинство инструментов для тестирования выдают результаты в формате Junit xml report. Это, позволяет сделать универсальные инструменты генерации отчётности по тестам, самый известный, наверное — Allure Framework.

В этой статье показано, как используют JSON-файлы, которые генерирует при работе Cucumber, как документация строится на основе логов, создаваемых в результате работы тестов.

Типовой пример создания документации на основе считывания состояния объектов, создаваемых в результате работы приложения, — документирование структуры БД. В конце раздела приведен пример, иллюстрирующий данный подход.

Исходный код сразу представляет собой структурированный формат

Многие языки уже реализованы в структурированном формате (например, xsd-схемы, OpenAPI, различные DSL для описания предметной области, файлы настроек).

Иногда проводят предварительную обработку этих форматов, например, объединение спецификации в единую иерархическую структуру (так называемая операция «flatten»).

Частным (и частым) случаем является ситуация, когда настройки содержатся в базе данных.

Пример — генерация документации по структуре базы данных

Пример иллюстрирует достаточно частую ситуацию, когда информация для документации хранится в таблицах СУБД.

Создаём скрипт, описывающий структуру БД. Этот скрипт не выглядит как исходник для поддержания структуры БД, однако, как это не парадоксально, таковым является, подробности в документации к уже упомянутому проекту. Это также может быть миграционный скрипт в любой системе контроля версии базы данных.

Применим скрипт к базе данных и воспользуемся двумя инструментами СУБД (пример приведён для PostgreSQL): динамическими представлениями для извлечения сведений о структуре и возможностью создавать JSON-файлы на основе результатов сохранения запросов.

В результате получим JSON-файл:

В следующем разделе будет показано, как этот файл превратить в документ.

Использование шаблонизаторов

Для превращения структурированного файла в документ используют специальный тип языков,
шаблонизаторы. Шаблонизатор позволяет задать правила обхода иерархической структуры данных и правила, по которым элементы иерархии исходного документа преобразуют в выходной документ.

Формат этих правил достаточно простой, они безопасны с точки зрения исполнения, поэтому часто шаблонизаторы используются для настройки различных аспектов работы приложений непосредственно пользователями.

Самым известным языком обработки шаблонов (но далеко не самым простым) является XSLT. Самым минималистичным — Mustache.

Свой язык написания шаблонов и шаблонизатор также создать довольно просто. Например, для создания системы генерации отчётов в форматах Excel и ods мы пошли этим путём.

Можно вообще обойтись без шаблонизатора, просто структурировать код определенным образом, в этой старой статье 2003 года Мартин Фаулер признается в нелюбви к XSLT и заодно объясняет, как его заменить кодом, написанным на языке Ruby. За 18 лет оказалось, что и статические языки также можно прекрасно использовать для этих целей, и XSLT прекрасно себя чувствует, и предложенный в статье подход оказался очень хорош.

В примерах будет использоваться Liquid для работы с JSON и XSLT для работы с XML. В обоих случаях будет использоваться реализация в Ruby, потому что (1) Наиболее распространенный в настоящий момент процессор Asciidoc — Asciidoctor — написан на Ruby (2) Ruby-скрипты отлично работают в java и javascript, что часто позволяет не плодить цирк технологий.

Пример генерации документа из JSON-файла

Рассмотрим простой пример по генерации документа на основе полученного выше JSON-файла.

Генерация диаграммы в формате PlantUML:

В примере шаблонизатор обходит все узлы, определяющие таблицы. Для каждой таблицы создается строка PlantUML для отрисовки классов class [Наименование класса] . Далее внутри каждой таблицы проверяется наличие внешних ключей и создается соединительная линия с соответствующими классами.

На выходе получаем следующий текст диаграммы:

Аналогично сгенерируем документ в формате Asciidoc:

Для объединения обоих кусков в один документ воспользуемся директивой include:

Синтаксис Asciidoc рассмотрен в статье Asciidoc для ЕСКД. Подробнее структурирование документации в Asciidoc планирую описать в отдельной статье. Здесь лишь хотелось бы отметить, что при вставке диаграммы мы указываем параметры её отображения. В разных документах одну и ту же диаграмму мы можем отобразить по-разному (в разных цветах, с разным разрешением, в разной ориентации и т.п.).

Результаты превращаем в файл в формате Microsoft Word с помощью проекта, о котором рассказано в предыдущей статье.

Ключевые техники, используемые при генерации документации

Для рассмотрения ключевых техник приведём пример с преобразованием XML-файла.

Для примера возьмем выписку из ЕГРЮЛ от Федеральной налоговой службы. Не совсем документация, но удобно для демонстрации основных приёмов преобразования структурированных данных в документацию.

Исходные данные (схема xsd и пример сообщения) взяты на сайте СМЭВ 3 — https://smev3.gosuslugi.ru/portal/inquirytype_one.jsp?id=41108&zone=fed. Для примера приведём небольшую часть выписки из ЕГРЮЛ:

Как видно, названия тэгов и атрибутов вполне говорящие, но мы возьмем полные названия параметров из схемы xsd.

Преобразование выписки из ЕГРЮЛ в формат Asciidoc выглядит следующим образом:

В примере шаблонизатор обходит все узлы файла с данными ЕГРЮЛ. Тэги, в которых есть атрибуты или дополнительные тэги трансформируются в заголовок с нужным уровнем иерархии. Атрибуты и текстовые тэги — в строки таблицы. Обратите внимание, что в Asciidoc реализован очень компактный способ задания ячейки таблицы через символ | .

Наименования тэгов и атрибутов XML-документа обёрнуты в фигурные скобки — специальный синтаксис для отображения значений атрибутов Asciidoc. Значения атрибутов легко извлекаем из xsd-схемы с помощью следующего преобразования:

Объединим полученные значения атрибутов Asciidoc (два файла, т.к. описание сервиса по выдаче ЕГРЮЛ состоит из двух схем xsd) и файл с содержанием выписки:

На выходе Microsoft Word даёт следующую картинку:

Борьба с пробельными символами

Поскольку конечным форматом преобразования является текстовая разметка, вопрос пробелов крайне важен: текст, смещенный на несколько пробелов, может быть воспринят как блок с моноширинным текстом.

Пробелы могут влиять на эстетику, читаемость и обрабатываемость выходного документа. Например, после каждого абзаца в Asciidoc должно быть два переноса строки. Их может быть и три, но читается файл хуже. Во многих автоматически сгенерированных документах количество переносов строк абсолютно не предсказуемо. Особенно это неудобно при сравнении версий файла. При наличии на выходе файла в формате XML или JSON можно было бы применить утилиты, создающие красивый выходной файл. Для текстовых маркапов, насколько я знаю, таких утилит не существует.

С другой стороны, крайне важно, чтобы сам шаблон был красивым и удобным для чтения и редактирования, чтобы, как минимум, были отступы в циклах и условных операторах.

Поработав со многими шаблонизаторами, пришёл к выводу, что единственный практически универсальный вариант — указать шаблонизатору, чтобы он вырезал все пробелы и переносы, а переносы указывать вручную в шаблоне. В приведенном примере есть опция и после каждой выводимой строчки помещена команда

. Некоторые шаблонизаторы воспринимают \n как символ переноса. Если нет, необходимо провести пост-обработку выходного файла и самостоятельно заменять данную комбинацию на перенос строки.

В примере для Liquid применен аналогичный подход, только для наглядности символ переноса присвоен переменной bl .

Рекурсия

Рекурсия обеспечивает наглядный способ обхода узлов структурированного документа с большим количеством единообразных уровней иерархии, как в приведённой выписке из ЕГРЮЛ.

Рекурсию поддерживает большинство шаблонизаторов. Например, XSLT поддерживает рекурсию директивой apply-templates . В примере основной шаблон ( template ) обеспечивает обработку иерархического узла выписки из ЕГРЮЛ и далее вызывает себя для каждого узла ниже по иерархии.

Экранирование и другие операции со вставляемыми данными

Данные для вставки в Asciidoc файл могут вступить в конфликт с разметкой Asciidoc. Например, вы хотите взять текст из Open API спецификации и добавить символ « ; ». Однако разработчик мог при описании сам поставить тот же символ. В результате в выходной файл попадёт два символа « ;; » и Asciidoc будет воспринимать текст как терминологический список, и хорошо ещё, если мы быстро поймём, почему на выходе текст отформатирован странно.

Чтобы этого избежать, можно оборачивать вставляемый текст собственными функциями, которые экранируют и производят требуемые преобразования значений. В примере — это функция iformat . Она добавляет в начале и в конце значения символ нулевого пробела (zero space) и переводит значения типа даты в формат DD.MM.YYYY.

Для полного отключения синтаксиса Asciidoc во вставляемых значениях, достаточно их просто экранировать.

Выводы

И анонс: следующая статья будет посвящена вопросам обеспечения качества документации в формате Asciidoc.

Источник

Оцените статью