|
Время бесплатного Офиса прошло. Применение свободного ПО становится востребованной альтернативой. При этом необходимы новые решения по интеграции приложений в единый комплекс. Одно из них основано на использовании широко используемого формата RTF.
Разработка прикладного ПО - это, как известно, не только написание кода программ, но и проектирование печатных документов и отчетов. Практически все интегрированные среды имеют в своем составе генераторы отчетов, в той или иной степени помогающие решить эту задачу. Однако, несмотря на явные достоинства, использование генераторов отчетов имеет ряд недостатков. Они сводятся, главным образом, к невозможности вносить правки в сформированный документ, а также изменять шаблоны отчета привычными средствами, например обычным текстовым редактором.
До последнего времени самым простым и широко применяемым решением представлялось применение механизма OLE. Например, для комбинации Word и VisualBasic возможна такая схема:
- 1. Создаем в отдельном файле шаблон документа. Там, где должна быть "шапка" (дата, номер документа и др.) используем закладки, а для основной части отчета создаем таблицу-заготовку соответствующей структуры. Пример такого шаблона приведен на рисунке.
- 2. Пишем программу с использованием объектной модели 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
|
- 3. Запускаем ее в составе всего приложения и получаем результат:
- 4. Пользователь, получив отчет в виде doc-файла, легко может внести в документ любые изменения, отправить его по электронной почте, распечатать - одним словом, распорядиться по своему усмотрению в привычной ему среде. Так же легко он может изменить и шаблон документа - для этого достаточно уметь работать в текстовом редакторе.
Но эту идиллическую картину омрачают несколько неприятных моментов. Во-первых, недостаточная гибкость приложения — если вы захотите перейти на другой редактор, то код придется писать заново. Во-вторых, приложение работает только в среде пакета MS Office - а он стоит немалых денег. Если приложение должно работать на тридцати компьютерах предприятия, то установка на них MS Office обойдется примерно в 40 тыс. гривен — не каждый бюджет выдержит.
В то же время существует целый ряд достаточно полнофункциональных и бесплатных офисных пакетов: OpenOffice, StarOffice, EasyOffice и др. Для большинства операций, выполняемых обычно с документами, их возможностей вполне достаточно.
Но возможна ли их простая и эффективная интеграция в прикладное программное обеспечение?
Решением этой проблемы может быть использование RTF-файлов. Этот формат, предложенный Microsoft как стандарт для обмена данными между текстовыми редакторами, поддерживается абсолютным большинством офисных пакетов. Сама Microsoft использует его в качестве формата, в котором данные передаются через буфер обмена между различными приложениями Windows.
Кратко об RTF
В формате RTF используются только коды, представляемыми символами из наборов ASCII, MAC и PC. Помимо текста, RTF-файл содержит команды управления в читаемой форме. Документ состоит преимущественно из команд управления настройкой программы чтения. Эти команды можно разделить на управляющие слова и управляющие символы.
Управляющее слово представляет собой последовательность символов с разделителем в конце. Например, фрагмент:
соответствует началу закладки ndoc.
Перед управляющим словом вводится обратная косая черта (\). В качестве разделителей могут использоваться следующие символы:
- пробел, причем он относится к управляющему слову;
- цифра или дефис (-). После этих символов должен следовать параметр с разделителем. В качестве разделителя может быть использован пробел или другие символы (кроме цифр и букв);
- все символы, кроме цифр и букв. Эти символы не относятся к управляющему слову.
Для задания управляющего слова в RTF-формате используются буквы от А до Z и от а до z, а также цифры от 0 до 9. Национальные символы к управляющей информации не относятся. В качестве управляющих символов используются отдельные буквы. Перед каждым таким символом вводится обратная косая черта (\). Например, фрагмент:
устанавливает шрифт №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} ...
|
Для решения данной задачи можно предложить следующий алгоритм:
- 1. Читаем последовательно строки входного файла (в большинстве случаев строка больше 255 символов).
- 2. Ищем в текущей строке тег '\bkmkstart'.
- 3. Если находим, то выделяем название закладки и сравниваем его с искомой.
- 4. Если совпадает, то записываем строковую строку данных после закрывающей скобки (}).
Алгоритм реализован в виде функции In_Zakl1(pth As String, zakl As String, data As String), где
- pth - имя RTF-файла,
- zakl - имя закладки,
- data - строка для добавления в файл.
Добавление строк в таблицу
Предположим, нам требуется найти m-ю строку в n-той таблице и повторить ее в этой таблице p раз.
Для поиска начала строки таблицы мы будем использовать тег '\intbl', а для поиска конца — тег '\row'. Конец самой таблицы определяется по последовательности тегов \row ... \pard ... \par ... \intbl.
Алгоритм решения этой задачи следующий:
- 1. Читаем последовательно строки входного файла.
- 2. Ищем последовательность \row ... \pard ... \par ... \intbl (не обязательно в одной строке) (n-1) раз. После этого мы находимся перед нужной таблицей.
- 3. Ищем тег '\row' (m-1) раз. После этого мы уже находимся перед нужной строкой таблицы.
- 4. Ищем следующий тег '\row' и копируем содержимое файла от (m-1)-го до m-го тега '\row' (между '\row' и '\intbl' содержатся настройки строки, они нам тоже нужны).
- 5. Вставляем после 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 } ...
|
Задача может быть решена по следующему алгоритму:
- 1. Читаем последовательно строки входного файла.
- 2. Ищем последовательность \row ... \pard ... \par ... \intbl (не обязательно в одной строке) (n-1) раз. После этого мы находимся перед нужной таблицей.
- 3. Ищем тег '\row' (m-1) раз. После этого мы уже находимся перед нужной строкой таблицы.
- 4. Ищем k-e вхождение тега '\cell'.
- 5. Вставляем перед ним нужную строку.
Данный алгоритм реализован в виде функции In_Tcell1(pth As String, itbl As Integer, irow As Integer, icell As Integer, ndata As String), где
- pth - имя RTF-файла,
- itbl - номер таблицы,
- irow - номер строки,
- icell - номер ячейки,
- ndata - строка для занесения в ячейку.
Программа на 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)
' для каждой строки в каждую ячейку вставляем нужные данные из массива
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 — как внешний файл.
Впрочем, эти проблемы решаются — стоит только приложить некоторые усилия.
05.2003
Файлы примеров. (350 Kb)
Александр Харьков aka 3ton or net3ton
|
|