Смекни!
smekni.com

Документация на основе RTF-шаблона (стр. 1 из 2)

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

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

До последнего времени самым простым и широко применяемым решением представлялось применение механизма 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. Национальные символы к управляющей информации не относятся.

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

…&bsol;f1&bsol;fs20…

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

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

&bsol;intbl&bsol;phmrg&bsol;posy371&bsol;dxfrtext180&bsol;dfrmtxtx180&bsol;dfrmtxty0&bsol;nowrap

&bsol;aspalpha&bsol;aspnum&bsol;faauto&bsol;adjustright&bsol;rin0&bsol;lin0&bsol;f1&bsol;fs20&bsol;lang1049

&bsol;langfe1049&bsol;cgrid&bsol;langnp1049&bsol;langfenp1049{&bsol;lang1033&bsol;langfe1049

&bsol;langnp1033 11&bsol;cell 12&bsol;cell 13&bsol;cell} &bsol;pard &bsol;ql &bsol;li0&bsol;ri0&bsol;widctlpar&bsol;intbl

&bsol;aspalpha&bsol;aspnum&bsol;faauto&bsol;adjustright&bsol;rin0&bsol;lin0

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

{группа}

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

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

&bsol;раr - конец абзаца;

&bsol;сеll - конец столбца;

&bsol;row - конец строки (или таблицы);

&bsol;*&bsol;bkmkstart <название закладки> &bsol;*&bsol;bkmkend - закладка. Пример: {&bsol;*&bsol;bkmkstart ndoc} BS190{&bsol;*&bsol;bkmkend ndoc};

&bsol;pard - устанавливает стандартную настройку для абзаца;

&bsol;intbl … &bsol;intbl - выделяет область таблицы;

&bsol;' - прямой ввод в текст шестнадцатеричных чисел. При сохранении кириллического текста он обычно сохраняется в шестнадцатеричной форме, например:

&bsol;'d1&bsol;'f2&bsol;'f0&bsol;'ee&bsol;'ea&bsol;'e0 ('строка')

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

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

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

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

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

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

Читаем последовательно строки входного файла (в большинстве случаев строка больше 255 символов).

Ищем в текущей строке тег '&bsol;bkmkstart'.

Если находим, то выделяем название закладки и сравниваем его с искомой.

Если совпадает, то записываем строковую строку данных после закрывающей скобки (}).

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

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

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

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

Читаем последовательно строки входного файла.

Ищем последовательность …&bsol;row…&bsol;pard…&bsol;par…&bsol;intbl… (не обязательно в одной строке) (n-1) раз. После этого мы находимся в начале нужной таблицы.

Ищем тег &bsol;row (m-1) раз. После этого находимся перед нужной строкой таблицы.

Ищем следующий тег &bsol;row и копируем содержимое файла от (m-1)-го до m-го тега &bsol;row (между &bsol;row и &bsol;intbl содержатся настройки строки, они нам тоже нужны).

Вставляем после m-го тега &bsol;row скопированную нами подстроку p раз.

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

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

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

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

...{&bsol;lang1033&bsol;cgrid0<содержимое 1-й ячейки>

&bsol;cell<содержимое 2-й ячейки>&bsol;cell}…

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

Читаем последовательно строки входного файла.

Ищем последовательность …&bsol;row…&bsol;pard…&bsol;par…&bsol;intbl… (не обязательно в одной строке) (n-1) раз. После этого мы находимся перед нужной нам таблицей.

Ищем тег &bsol;row (m-1) раз. После этого мы находимся в начале нужной строки таблицы.

Ищем k-e вхождение тега &bsol;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 = "Петров И.И."