File Coverage

blib/lib/Net/Z3950/AsyncZ/Report.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             # $Date: 2003/12/05 17:02:57 $
2             # $Revision: 1.6 $
3              
4             our $VERSION = '0.02';
5             package Net::Z3950::AsyncZ::Report;
6 1     1   1524 use Net::Z3950;
  0            
  0            
7             use MARC::Base;
8              
9             use strict;
10              
11             my %MARC_FIELDS_STD = (
12             "020"=>'ISBN',
13             "050"=>"LC call number",
14             100=>'author',
15             245=>'title',
16             250=>'edition',
17             260=>'publication',
18             300=>'description',
19             440=>'series',
20             500=>'note',
21             520=>'annotation',
22             650=>'subject',
23             700=>'auth, illus, ed',
24             );
25              
26             my %MARC_FIELDS_XTRA = (
27            
28             "082"=>'Dewey decimal number',
29             240=>'Uniform title',
30             246=>'alternate title',
31             130=>'main entry',
32             306=>'playing time',
33             504=>'Bibliography',
34             508=>'creation/production credits',
35             510=>'citation/references',
36             511=>'participant or performer',
37             520=>'Summary,note',
38             521=>'target audience',
39             530=>'physical form',
40             586=>'awards'
41             );
42              
43             my %MARC_FIELDS_ALL = (%MARC_FIELDS_STD, %MARC_FIELDS_XTRA);
44              
45             use vars qw(%MARC_FIELDS);
46             %MARC_FIELDS = %MARC_FIELDS_STD;
47              
48             use vars qw($std $xtra $all);
49             $std = \%MARC_FIELDS_STD;
50             $xtra = \%MARC_FIELDS_XTRA;
51             $all = \%MARC_FIELDS_ALL;
52              
53             {
54              
55             my $_marc_sep = "MARC";
56             my $_grs_sep = "GRS-1";
57             my $_raw_sep = "RAW";
58             my $_def_sep = "DEFAULT";
59              
60              
61             sub _get_MARCsep { $_marc_sep; }
62             sub _get_GRSsep { $_grs_sep; }
63             sub _get_RAWsep { $_raw_sep; }
64             sub _get_DEFAULTsep { $_def_sep; }
65              
66             sub get_MARC_pat { _get_pat (_get_MARCsep()) }
67             sub get_GRS1_pat { _get_pat (_get_GRSsep()) }
68             sub get_RAW_pat { _get_pat (_get_RAWsep()) }
69             sub get_DEFAULT_pat { _get_pat (_get_DEFAULTsep()) }
70             sub get_pats { get_MARC_pat() . '|' . get_GRS1_pat() . '|' . get_RAW_pat() . '|' . _get_DEFAULTsep()}
71              
72             sub _get_pat {
73             my ($pat) = @_;
74             return '\[' . $pat . '\s\d+\]';
75             }
76              
77             }
78              
79             ##
80             ## params
81             ## $num_to_fetch: number of records to retrieve in current pass
82             ## format => undef, # reference to a callback function that formats each row of a record
83             ## raw => 0, # (boolean) if true the raw record data is returned unformatted
84             ## start => 1, # number of the record with which to start report
85             ## num_to_fetch => 5, # number of records to include in a report
86             ## marc_fields => $std, # default: $std, others are $xtra or $all
87             ## marc_xcl => undef, # reference to hash of MARC fields to exclude from report
88             ## marc_userdef => undef, # reference to user specified hash of MARC fields for report
89             ## marc_subst => undef # reference to a hash which subtitutes field names for default names
90             ## HTML =>0 # (boolean) if true use default HTML formatting,
91             # if false format as plain text
92             # if true each row will be formatted as follows:
93             # "
field namefield data\n"
94             # if false each row will be formatted as follows:
95             # "MARC_field_number field_name field_data\n"
96              
97             ## record row priority sequence: raw, format, HTML, plaintext
98              
99             ##marc_xcl: the hash values can be in any form, as long as the keys pass
100             ## the exists test: if exists $marc_xcl->{ $key }:
101            
102             ## { '020'=>"", 500=>"", 300=>undef, 520=>'annotation' }
103              
104             ## the key is always three digits;
105             ## if the first digit is 0, then the key must be enclosed
106             ## in quotation marks
107             ##
108             ## marc_userdef this allows the user to specify which fields to include in the report
109             ## and what names are to be used for them
110             ##
111             ## marc_subst enables user-defined field names, for instance, where the defualt is:
112             ## 250=>'edition', 650=>'subject'
113             ## a hash can be specfied with substitutions:
114             ## { 250=>'ed.', 650=>'subj.'}
115            
116            
117             ## marc fields priority sequence: marc_userdef, marc_fields, marc_xcl, marc_subst
118             ## This means that
119             ## 1. marc_userdef will replace marc_fields if marc_userdef exists
120             ## 2. marc_xcl will be applied to the hash which results from operation 1
121             ## 3. marc_subst will be applied to the hash resulting from 1 plus 2
122              
123              
124              
125             # Internal Params:
126             # $rs: record set
127             # recnum: number of records in record set
128             # result: array of record data to be returned (reference) --
129             # each line in record is treated as array element
130             # except for return of raw data which is pushed
131             # in the format returned from record->render(),
132             # which is itself an array
133             #
134              
135             # options: a _params object
136            
137             sub new {
138             my ($class, $rs, $options) = @_;
139              
140             my $self = {
141             rs=>$rs,
142             recnum=>$rs->size(),
143             result=>[],
144             format => undef,
145             raw => 0,
146             startrec => 1,
147             marc_fields => $std,
148             marc_xcl => undef,
149             marc_userdef => undef,
150             marc_subst => undef,
151             HTML =>0,
152             render => 1, # default is to use record->render() on raw record output
153             _this_server => undef,
154             _this_pid => undef,
155             num_to_fetch => 5
156             };
157              
158              
159             my $update = $options->_updateObjectHash($self);
160             $self = {%$self,%$update};
161              
162             $self->{marc_fields} = $self->{marc_userdef} if defined $self->{marc_userdef};
163              
164             if(defined $self->{marc_xcl}) {
165             foreach my $opt(keys %{$self->{marc_fields}}) {
166             delete $self->{marc_fields}->{$opt} if exists $self->{marc_xcl}->{$opt};
167             }
168             }
169              
170             if(defined $self->{marc_subst}) {
171             foreach my $opt(keys %{$self->{marc_subst}}) {
172             $self->{marc_fields}->{$opt} = $self->{marc_subst}->{$opt}
173             if defined $self->{marc_subst}->{$opt}
174             && defined $self->{marc_fields}->{$opt};
175             }
176             }
177              
178             %MARC_FIELDS = %{$self->{marc_fields}} if $self->{marc_fields};
179            
180             bless $self, $class;
181             }
182              
183              
184             sub reportResult {
185              
186             my ($self) = @_;
187             my $rs = $self->{rs};
188             my $found = 0;
189             my $numErrors=0;
190              
191             my $start = $self->{startrec};
192             my $num_to_fetch = $self->{startrec} + $self->{num_to_fetch}-1;
193              
194              
195              
196             if($num_to_fetch > $self->{recnum}) {
197             $num_to_fetch = $self->{recnum};
198             $start = $num_to_fetch - $self->{num_to_fetch};
199             $start = 1 if $start < 1;
200             }
201              
202              
203             $rs->present($start, $num_to_fetch);
204              
205              
206             foreach my $i ($start..$num_to_fetch) {
207              
208             my $rec = $rs->record($i);
209              
210             if (!defined $rec) {
211             if($numErrors > 2) {
212             Net::Z3950::AsyncZ::Errors::report_error($rs);
213             }
214             $numErrors++;
215             next;
216             }
217              
218            
219             my $raw = $rec->rawdata();
220              
221             $found = 1;
222              
223             if ($self->{raw}) {
224             $self->{'render'} ? $self->printRenderedRaw($rec,$i) : $self->printRaw($raw, $i);
225             }
226             elsif ($rec->isa('Net::Z3950::Record::GRS1')) {
227             # raw data for GRS-1 is reference to Net::Z3950::Record object
228             $self->printGRS_1($raw, $i);
229             }
230             elsif ($rec->isa('Net::Z3950::Record::USMARC')) {
231             # raw data for MARC record is string w/o new-lines
232             $self->printMARCRecord($raw, $i);
233             }
234             else {
235             # pass in a Net::Z3950::Record which can then call render()
236             $self->defaultPrintRec($rec, $i);
237             }
238              
239             }
240              
241             return $found;
242             }
243              
244              
245              
246             sub _defaultRecordRowHTML {
247             my ($row) = @_;
248             return "
" . $MARC_FIELDS{$row->[0]} . "" . $row->[1] . "\n";
249             }
250              
251              
252             sub _defaultRecordRow {
253             my ($row) = @_;
254             return $row->[0] . "\t" . $MARC_FIELDS{$row->[0]} . ":\t" . $row->[1] . "\n";
255            
256             }
257              
258              
259             sub _formatRecordRow {
260             my ($self,$row) = @_;
261             my $str;
262              
263             if(defined $self->{format}) {
264             $str = $self->{format}->($row);
265             chomp $str; $str .= "\n"; # need nl for splitting into array but only one nl!
266             }
267             elsif($self->{HTML}) {
268             $str = _defaultRecordRowHTML($row);
269             }
270             else {
271             $str = _defaultRecordRow($row);
272             }
273              
274             push(@{$self->{result}},$str);
275             }
276              
277             # new record header: [TYPE RECORD_NUMBER], e.g [MARC 1]
278             sub _newRec {
279             my($self, $type, $recnum) = @_;
280             push(@{$self->{result}}, "", "\n");
281             push(@{$self->{result}}, "<#--" . $self->{_this_pid} . "-->", "\n");
282             push(@{$self->{result}},"[$type $recnum]\n");
283             }
284            
285             sub defaultPrintRec {
286             my $self = shift;
287             my $record = shift;
288             my $recnum = shift;
289              
290            
291             my $recString = $record->render();
292             my @recArray = split /\n/, $recString;
293             return if scalar @recArray < 2;
294              
295             $self->_newRec(_get_DEFAULTsep(), $recnum);
296             foreach my $field(@recArray) {
297             $field =~ s/[\_\|\$]./ /g;
298             $field =~ s/\"//g;
299             my $id;
300             if($field =~ /^\(/) {
301             $field =~ s/^\(\d+,\s*(\d+)\)\s+//;
302             $id = $1;
303             }
304             else {
305             $field =~ s/^(\d+)\s+\d*//;
306             $id = $1;
307             }
308             if($id && exists $MARC_FIELDS{$id}) {
309             $self->_formatRecordRow([$id, $field]);
310             }
311             elsif(!$id) {
312             $self->_formatRecordRow(["", $field]);
313             }
314             }
315              
316             }
317              
318              
319             sub printGRS_1 {
320             my $self = shift;
321             my $record = shift;
322             my $recnum = shift;
323              
324             $self->_newRec(_get_GRSsep(), $recnum);
325              
326             # $record is a reference to an array of elements,
327             # each representing one of the fields of the record.
328              
329             my $recString = $record->render();
330             my @recArray = split /\n/, $recString;
331              
332             foreach my $i (1..scalar (@recArray)-1) {
333             my $field = $recArray[$i];
334             $field =~ s/^\(\d+,\s*(\d+)\)\s+//;
335             my $id = $1;
336             if($id && exists $MARC_FIELDS{$id}) {
337             $field =~ s/\_./ /g;
338             $field =~ s/\"//g;
339             $self->_formatRecordRow([$id, $field]);
340             }
341             # this is a hack for something that needs
342             # a more sophisticated response, one that will acutally read the
343             # GRS-1 fields that the Marc tags don't represent
344             elsif($id && $self->{marc_fields} != $std) {
345             $field =~ s/\_./ /g;
346             $field =~ s/\"//g;
347             push(@{$self->{result}},$field, "\n");
348             }
349             }
350              
351              
352             }
353              
354              
355             sub printRaw {
356             my $self = shift;
357             my $raw = shift;
358             my $recnum = shift;
359             $self->_newRec(_get_RAWsep(), $recnum);
360             push(@{$self->{result}},$raw);
361             }
362              
363              
364             sub printRenderedRaw {
365             my $self = shift;
366             my $record = shift;
367             my $recnum = shift;
368              
369             $self->_newRec(_get_RAWsep(), $recnum);
370             push(@{$self->{result}},$record->render());
371             }
372              
373              
374             sub printMARCRecord {
375              
376             my $self = shift;
377             my $record = shift;
378              
379             my $recnum = shift;
380             my @marc_array = &marc2array ($record);
381             $self->_newRec(_get_MARCsep(), $recnum);
382              
383             foreach my $f(@marc_array) {
384              
385             next if $f=~ /^LDR/;
386             $f=~ s/(\d+)\s+\d*//;
387             my $id = $1;
388              
389             if( exists $MARC_FIELDS{$id}) {
390             $f=~ s/\|./ /g;
391             $f=~s/^ +/ /;
392             $self->_formatRecordRow([$id, $f]);
393             }
394             }
395              
396             }
397              
398              
399              
400             1;
401              
402              
403             __END__