Простой способ подготовки отчетов на основе rtf-бланков

от автора

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

Пример rtf-бланка
Заголовок документа: PARAM1

Строка 1 Значение PARAM2
Строка 2 Значение PARAM3

Подпись под документом: PARAM4

Рис.1 Пример бланка в виде rtf-файла, переменные описаны в виде полей типа “QUOTE” – PARAM1,PARAM2,PARAM3,PARAM4

При заполнении бланка данными, переменные PARAM1…4 должны будут замениться на свои значения.
При этом форма бланка обычно остается постоянной и неизменной, а конкретные поля в бланке необходимо “подгружать” из таблиц баз данных, файлов с данными и т.д. В терминах языка Perl – значениями хеша, ключи которого соответствуют названиям переменных:
(PARAM1=>”ПАРАМЕТР1”, PARAM1=>”ПАРАМЕТР2”, PARAM1=>”ПАРАМЕТР3”,
PARAM1=>”ПАРАМЕТР4”)
В результате, готовый к печати на лазерном принтере бланк, будет иметь примерно такой вид:

Пример rtf-бланка
Заголовок документа: ПАРАМЕТР1

Строка 1 Значение ПАРАМЕТР2
Строка 2 Значение ПАРАМЕТР3

Подпись под документом: ПАРАМЕТР4

Рис.2 Результат заполнения rtf-бланка (рис.1) заменой полей типа “QUOTE” на значения соответствующих ключей хеша.

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

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

Другой вариант – использование бланков в форме XML-файлов и заполнение их в соответствии с правилами подстановки, описанными в XSLT-таблицах,- имеет тот недостаток, что неподготовленному пользователю, привыкшему работать с MS Word будет трудно создавать и редактировать бланки XML-файлов. Какой-либо общераспространенный инструмент для работы с XML, сравнимый по популярности с MS Word трудно найти.

Выходом, разработанным и апробированным уже в течение ряда лет при работе в крупной банковской информационной системе стал вариант автоматической подстановки данных в rtf-бланки отчетов с использованием простого скрипта (в данном случае использовался perl, но возможно использование любого языка, поддерживающего обработку регулярных выражений), осуществляющего поиск в текстовом rtf-документе описателей полей типа “QUOTE” и замену символических названий этих полей на значение переменной с аналогичным именем, извлеченной из таблицы БД, файла данных (в терминах perl – из хеша по ключу, соответствующему символическому названию поля).

Пример скрипта c комментариями, выполняющего подобную подстановку, приведен в конце постинга.

Скорее всего, даже краткого пояснения принципа работы скрипта не требуется (готовый rtf-бланк с выполненными подстановками значений переменных выводится во временный файл temp.rtf, подготовленный к отправке на принтер), единственная представляющая в нем интерес часть – регулярное выражение:

$rtf =~ s/\{\\field\b[^{}]*\{\\\*\\fldinst.*?{\\fldrslt\s*\{([^}]+\s)?\s*([^}]+\s) ?\s*([^}]+)\}\s*((?:\{[^{}]+\}\s*)*)\}\s*\}/dosubst($1,$2,$3,$p,$&)/gesx; 

осуществляющее поиск в rtf-файле описателей полей типа “QUOTE” и замену их соответствующим значением из хеша %p, возвращаемым функцией dosubst. Работоспособность этого регулярного выражения проверена на rtf-файлах, подготавливаемых всеми пакетами MS Office – от Office 95 до Office 2010.

Конечно, данный способ имеет некоторые недостатки, например, довольно трудно осуществлять вывод в rtf-бланк табличных значений, особенно для длинных таблиц, (их, например, можно выводить сразу в готовом виде, строя в perl-скрипте), но имеет и серьезные плюсы:

— разработку бланка и расстановку в нем полей для размещения данных может выполнять обычный пользователь, знакомый с редактором Word (умеющий вставлять в текст поля типа “QUOTE”), сообщающий затем список названий полей данных и что в них желательно помещать при подстановке программисту или специалисту службы поддержки;
— разработку скрипта, выгружающего данные, осуществляет программист, а в дальнейшем, при необходимости косметических изменений бланка (шрифт, отступы, логотип и т.д.), программиста привлекать необходимости нет, с этой работой легко справляется или служба поддержки, или сам пользователь – автор бланка.

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

#!/usr/bin/perl # filling rtf-blank # Dim Kobzev, Andrew Sapognikov # 2004  $==1000; #-------------------------filling template file------------------------------- sub dosubst {     my ($pfx, $key, $xtrakey, $parm, $str) = @_;     if (defined $xtrakey) {         $xtrakey =~ s/[{}]//g;         $xtrakey =~ s/\\w+//g;         $xtrakey =~ s/\s//g;         $key .= $xtrakey;     }     defined ($parm->{$key}) or return "\{$pfx\}";     my $val = $parm->{$key};     $val =~ s/([{}\\])/\\$1/g;     $val =~ s/\n/\\line/g;     $val =~ s/\r//g;     return "\{$pfx$val\}"; }  sub template ($$) { #filling $filename with hash $p  my ($filename,$p)=@_;  my $rtf;  local $/, *F;  open (F,"< $filename") or die "Cannot open $filename";  $rtf=<F>; close(F);  #set win-1251 codepage  $rtf =~ s/\\f(5|6)\\fmodern\\fcharset0/\\f$1\\fmodern\\fcharset144/;  $rtf =~ s/\{\\field\b[^{}]*\{\\\*\\fldinst.*?{\\fldrslt\s*\{([^}]+\s)  ?\s*([^}]+)\}\s*((?:\{[^{}]+\}\s*)*)\}\s*\}/dosubst($1,$2,$3,$p,$&)/gesx;  return $rtf; };  #-------------------------main-------------------------------------------------- %p=('PARAM1'=>"ПАРАМЕТР1",'PARAM2'=>"ПАРАМЕТР2", 'PARAM3'=>"ПАРАМЕТР3",'PARAM4'=>"ПАРАМЕТР4"); my $tfil='temp.rtf'; open *FILE, "> $tfil"   or die "Cannot open temporary file $tfil"; print FILE template("blank.rtf",\%p); close *FILE; #---------------------------------end main-------------------------------------  

ссылка на оригинал статьи http://habrahabr.ru/post/156805/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *