Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
Конференция «Технологии управления данными 2018»
СУБД, платформы, инструменты, реальные проекты.
29 ноября 2018 г.
2004 г.

Документация на основе RTF-шаблона

Александр Харьков, "Комиздат"

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

До последнего времени самым простым и широко применяемым решением представлялось применение механизма OLE. Например, для комбинации Word и VisualBasic возможна такая схема:

  • Создаем некий файл - шаблон документа. Там, где должна быть "шапка" (дата, номер документа и др.), используем закладки, а для основной части отчета создаем таблицу-заготовку соответствующей структуры. Пример такого шаблона приведен на рис. 1.
  • Пишем программу с использованием объектной модели Word:

' NumStr - кол-во строк в отчете
' NewData (5,NumStr) - массив с данными для заполнения
' таблицы, заранее приведенными к символьному виду
' Itog - сумма, приведенная к символьному виду
' Pth - путь к исходному файлу
' Str_ndoc = "BS190"
' Str_name = "Петров И.И."
.................

Dim objWord As Word.Application
Dim objDoc As Word.Document
Dim objTable As Word.Table

' создаем объект Word
Set objWord = New Word.Application
' делаем его видимым - это не обязательно,
' но очень интересно :)
objWord.Visible = True

' открываем файл шаблона
Set objDoc = objWord.Documents.Open (Pth)
' делаем его активным
objDoc.Activate

' заполняем "шапку документа" - номер и получатель
' - закладки 'ndoc' и 'name' соответственно
objDoc.Bookmarks ("ndoc").Range.Text = Str_ndoc
objDoc.Bookmarks ("name").Range.Text = Str_name

' связывам объект с таблицей
Set objTable = objWord.ActiveDocument.Tables (1)

' выделяем 2-ю строку таблицы в шаблоне
objTable.Cell (2, 1).Range.Select

' вставляем нужное кол-во строк-1
' (т.к. одна уже есть в шаблоне)
If NumStr > 0 Then objWord.Selection.InsertRows (NumStr - 1)

' для каждой строки в каждую ячейку вставляем нужные
' данные из массива
For i = 1 To NumStr
For j = 1 To 5
objTable.Cell (i + 1, j).Range.Text = NewData (j, i)
Next j
Next i

' проставляем сумму "Всего"
objTable.Cell (NumStr + 2, 5).Range.Text = Itog

  • Запускаем ее в составе всего приложения и получаем результат (см. рис. 2).
  • Пользователь, получив отчет в виде doc-файла, может легко внести в документ любые изменения, отправить его по электронной почте, распечатать - одним словом, распорядиться по своему усмотрению в привычной ему среде. Так же легко он может изменить и шаблон документа - для этого достаточно уметь работать в текстовом редакторе.

Но эту идиллическую картину омрачает несколько неприятных моментов. Во-первых, недостаточная гибкость приложения - если вы захотите перейти на другой редактор, то придется писать код заново. Во-вторых, приложение работает только в среде пакета MS Office, а он стоит немалых денег. Если приложение должно работать на 30-ти компьютерах предприятия, то установка на них MS Office обойдется примерно в 40 тыс. гривен - не каждый бюджет выдержит.

В то же время существует целый ряд бесплатных и достаточно полнофункциональных офисных пакетов: OpenOffice, StarOffice, EasyOffice и др. Для большинства операций, выполняемых обычно с документами, их возможностей вполне достаточно. Но возможна ли их простая и эффективная интеграция в прикладное программное обеспечение?

Решением этой проблемы может быть использование RTF-файлов. Этот формат, предложенный Microsoft как стандарт для обмена данными между текстовыми редакторами, поддерживается абсолютным большинством офисных пакетов. Сама Microsoft использует его в качестве формата, в котором данные передаются через буфер обмена между различными приложениями Windows.

Кратко об RTF

В формате RTF используются только коды, представляемые символами из наборов ASCII, MAC и PC. Помимо текста, RTF-файл содержит команды управления в читаемой форме. Документ состоит преимущественно из команд управления настройкой программы чтения. Эти команды можно разделить на управляющие слова и управляющие символы.

Управляющее слово представляет собой последовательность символов с разделителем в конце. Например, фрагмент:

…\bkmkstart ndoc…

соответствует началу закладки ndoc.

Перед управляющим словом вводится обратная косая черта (\). В качестве разделителей могут использоваться следующие символы:

  • пробел, причем этот символ относится к управляющему слову;
  • цифра или дефис (<->). После этих символов должен следовать параметр с разделителем. В качестве разделителя может быть использован пробел или другие символы (кроме цифр и букв);
  • все символы, кроме цифр и букв. Эти символы не относятся к управляющему слову.

Для задания управляющей последовательности в RTF-формате используются буквы от А до Z и от а до z, а также цифры от 0 до 9. Национальные символы к управляющей информации не относятся.

В качестве управляющих символов используются отдельные буквы. Перед каждым управляющим символом вводится обратная косая черта (\). Например, фрагмент:

…\f1\fs20…

устанавливает шрифт № 1 размером в 20 единиц.

Фрагмент RTF-файла приведен ниже. Структура его, как можно видеть, напоминает структуру HTML-документа:

\intbl\phmrg\posy371\dxfrtext180\dfrmtxtx180\dfrmtxty0\nowrap
\aspalpha\aspnum\faauto\adjustright\rin0\lin0\f1\fs20\lang1049
\langfe1049\cgrid\langnp1049\langfenp1049{\lang1033\langfe1049
\langnp1033 11\cell 12\cell 13\cell} \pard \ql \li0\ri0\widctlpar\intbl
\aspalpha\aspnum\faauto\adjustright\rin0\lin0

В RTF-формате существует возможность объединять отдельные последовательности в группы при помощи скобок:

{группа}

Такие группы создаются, например, при описании сносок, колонтитулов, закладок и т.п.

Вот некоторые управляющие слова и символы, имеющие непосредственное отношение к теме нашей статьи:

  • \раr - конец абзаца;
  • \сеll - конец столбца;
  • \row - конец строки (или таблицы);
  • \*\bkmkstart <название закладки> \*\bkmkend - закладка. Пример: {\*\bkmkstart ndoc} BS190{\*\bkmkend ndoc};
  • \pard - устанавливает стандартную настройку для абзаца;
  • \intbl … \intbl - выделяет область таблицы;
  • \' - прямой ввод в текст шестнадцатеричных чисел. При сохранении кириллического текста он обычно сохраняется в шестнадцатеричной форме, например:
\'d1\'f2\'f0\'ee\'ea\'e0 ('строка')

Поскольку нас интересуют только определенные задачи, знания приведенных выше управляющих слов и символов вполне достаточно. Условимся для простоты называть управляющие слова и символы тегами.

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

Вставка строки на месте закладки

Пример такой закладки:

…{\*\bkmkstart ndoc}<значение закладки>{\*\bkmkend ndoc}…

Для решения данной задачи можно предложить следующий алгоритм.

  • Читаем последовательно строки входного файла (в большинстве случаев строка больше 255 символов).
  • Ищем в текущей строке тег '\bkmkstart'.
  • Если находим, то выделяем название закладки и сравниваем его с искомой.
  • Если совпадает, то записываем строковую строку данных после закрывающей скобки (}).

Алгоритм реализован в виде функции In_Zakl1(pth As String, zakl As String, data As String), где pth - имя RTF-файла, zakl - имя закладки, data - строка для добавления в файл.

Добавление строк в таблицу

Предположим, нам требуется найти m-ю строку в n-той таблице и повторить ее в этой таблице p раз. Для поиска начала строки таблицы мы будем использовать тег \intbl, а для поиска конца - тег \row. Конец самой таблицы определяется по последовательности тегов \row…\pard…\par.

Алгоритм решения этой задачи следующий.

  • Читаем последовательно строки входного файла.
  • Ищем последовательность …\row…\pard…\par…\intbl… (не обязательно в одной строке) (n-1) раз. После этого мы находимся в начале нужной таблицы.
  • Ищем тег \row (m-1) раз. После этого находимся перед нужной строкой таблицы.
  • Ищем следующий тег \row и копируем содержимое файла от (m-1)-го до m-го тега \row (между \row и \intbl содержатся настройки строки, они нам тоже нужны).
  • Вставляем после m-го тега \row скопированную нами подстроку p раз.

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

Алгоритм реализован в виде функции In_TStr (pth As String, itbl As Integer, irow As Integer, kol As Integer), где pth - имя RTF-файла, itbl - номер таблицы, irow - номер строки, kol - количество повторов строки.

Заполнение ячейки таблицы

Представим, что требуется найти k-ю ячейку в m-й строке n-й таблицы и вставить в нее текстовую строку данных. Пример таких ячеек:

...{\lang1033\cgrid0<содержимое 1-й ячейки>
\cell<содержимое 2-й ячейки>\cell}…

Задача может быть решена по следующему алгоритму.

  • Читаем последовательно строки входного файла.
  • Ищем последовательность …\row…\pard…\par…\intbl… (не обязательно в одной строке) (n-1) раз. После этого мы находимся перед нужной нам таблицей.
  • Ищем тег \row (m-1) раз. После этого мы находимся в начале нужной строки таблицы.
  • Ищем k-e вхождение тега \cell.
  • Вставляем перед ним строку данных.

Данный алгоритм реализован в виде функции In_Tcell1(pth As String, itbl As Integer, irow As Integer, icell As Integer, ndata As String), где pth - имя RTF-файла, itbl - номер таблицы, irow - номер строки, icell - номер ячейки, data - строка для занесения в ячейку.

Программа на VisualBasic, демонстрирующая применение такой технологии и функционально идентичная программе, приведенной в начале этой статьи, выглядит так:

' NumStr - кол-во строк в отчете
' NewData (5,NumStr) - массив с данными для заполнения
' таблицы, заранее приведенными к символьному виду
' Itog - сумма, приведенная к символьному виду
' pth - путь к файлу
' Str_ndoc = "BS190"
' Str_name = "Петров И.И."

Dim res As Boolean   ' результат выполнения функций

' заполняем "шапку документа" - номер и получатель
' - закладки 'ndoc' и 'name' соответственно

res = In_Zakl1(pth, "ndoc", Str_ndoc)
res = In_Zakl1(pth, "name", Str_name)

' вставляем нужное кол-во строк-1
' (т.к. одна уже есть в шаблоне)
res = In_TStr (pth, 1, 2, NumStr - 1)

' для каждой строки в каждую ячейку вставляем
' нужные данные из массива

For i = 1 To NumStr
For j = 1 To 5
res = In_Tcell1(pth, 1, i + 1, j, NewData (j, i))
Next j
Next i

res = In_Tcell1(pth, 1, NumStr + 2, 5, Itog)
' проставляем сумму "Всего"

Заключение

Каковы преимущества и недостатки предложенной технологии? Начнем с достоинств. Во-первых, это более гибкая технология для формирования отчетов - даже если часть пользователей работает с OpenOffice, а часть с MS Office, программа создания отчетных документов универсальна. Во-вторых, несмотря на многоразовую перезапись файла шаблона во время работы, эта программа работает быстрее, чем связка OLE+Word. Тем более что приведенные выше алгоритмы могут совершенствоваться. Один из примеров кардинального повышения производительности приведен в листингах варианта для PascalDelphi. В-третьих, пользуясь свободным ПО, вы экономите деньги.

Теперь о проблемах. Основная из них - это недостаточная стандартизация формата RTF. Производители ПО, в целом придерживаясь единого стандарта, допускают несколько свободную трактовку частных моментов. Результат - проблемы с использованием "чужих" RTF-файлов, подготовленных в других редакторах. Например, MS Word сохраняет графические изображения внутри RTF-файла в виде последовательности шестнадцатеричных кодов, а OOWriter - как внешний файл.

Впрочем, эти проблемы решаются - стоит только приложить некоторые усилия.

Новости мира IT:

Архив новостей

Последние комментарии:

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 985 1945361
Пресс-релизы — pr@citforum.ru
Обратная связь
Информация для авторов
Rambler's Top100 TopList liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2015 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...