Как стать автором
Обновить

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

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

Пример 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-------------------------------------

Теги:
Хабы:
Всего голосов 18: ↑15 и ↓3+12
Комментарии16

Публикации

Ближайшие события