/[webpac2]/trunk/lib/WebPAC/Input/DBF.pm
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/lib/WebPAC/Input/DBF.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 869 - (show annotations)
Thu Jun 21 21:26:19 2007 UTC (16 years, 11 months ago) by dpavlin
File size: 4604 byte(s)
 r1290@llin:  dpavlin | 2007-06-21 23:26:25 +0200
 experimental (still unfinished) dbf input

1 package WebPAC::Input::DBF;
2
3 use warnings;
4 use strict;
5
6 use WebPAC::Input;
7 use base qw/WebPAC::Common/;
8 use XBase;
9 use Data::Dump qw/dump/;
10 use Encode qw/encode_utf8/;
11 use YAML;
12 use File::Slurp;
13
14 =head1 NAME
15
16 WebPAC::Input::DBF - support for reading DBF tables
17
18 =head1 VERSION
19
20 Version 0.01
21
22 =cut
23
24 our $VERSION = '0.01';
25
26 =head1 SYNOPSIS
27
28 Read data from DBF tables (do you remember Clipper applications?) and create
29 pseudo-MARC records from them.
30
31 my $ll_db = new WebPAC::Input::DBF(
32 path => '/path/to/database.dbf',
33 );
34
35 =head1 FUNCTIONS
36
37 =head2 new
38
39 Returns new low-level input API object
40
41 my $ll_db = new WebPAC::Input::DBF(
42 path => '/path/to/database.dbf'
43 filter => sub {
44 my ($l,$field_nr) = @_;
45 # do something with $l which is line of input file
46 return $l;
47 },
48 }
49
50 Options:
51
52 =over 4
53
54 =item path
55
56 path to DBF file
57
58 =back
59
60 =cut
61
62 sub new {
63 my $class = shift;
64 my $self = {@_};
65 bless($self, $class);
66
67 my $arg = {@_};
68
69 my $log = $self->_get_logger();
70
71 my $db = XBase->new( $arg->{path} ) || $log->logdie("can't open ", $arg->{path}, ": $!");
72
73 my $size = $db->last_record;
74
75 $log->info("opening DBF database '$arg->{path}' with $size records");
76
77 my $mapping = $arg->{input_config}->{mapping};
78
79 if ( ! $mapping ) {
80 $log->debug("didn't found any mapping file in configuration", sub { dump( $arg->{input_config} ) });
81
82 foreach my $field ( $db->field_names ) {
83 push @$mapping, { $field => { '900' => 'x' } };
84 }
85
86 my $mapping_path = $arg->{path};
87 $mapping_path =~ s!^.+/([^/]+)\.dbf!$1.yml!;
88
89 $log->logdie("mapping file $mapping_path allready exists, aborting.") if ( -e $mapping_path );
90
91 write_file( $mapping_path, Dump( { mapping => $mapping } ) ) ||
92 $log->logdie("can't write template file for mapping_path $mapping_path: $!");
93
94 $log->logdie("template file for mapping_path created as $mapping_path");
95
96 } else {
97 $log->debug("using mapping ", sub { dump($mapping) });
98 }
99
100 foreach my $mfn ( 1 .. $size ) {
101
102 my $row = $db->get_record_as_hash( $mfn );
103
104 $log->debug("dbf row = ", sub { dump( $row ) });
105
106 my $record = {
107 '001' => [ $mfn ],
108 };
109
110 $self->{_rows}->{ $mfn } = $record;
111 $log->debug("created row $mfn ", dump( $record ));
112 }
113
114 $self->{size} = $size;
115
116 $self ? return $self : return undef;
117 }
118
119 =head2 fetch_rec
120
121 Return record with ID C<$mfn> from database
122
123 my $rec = $ll_db->fetch_rec( $mfn, $filter_coderef );
124
125 =cut
126
127 sub fetch_rec {
128 my $self = shift;
129
130 my ($mfn, $filter_coderef) = @_;
131
132 my $rec = $self->_to_hash(
133 mfn => $mfn,
134 row => $self->{_rows}->{$mfn},
135 hash_filter => $filter_coderef,
136 );
137
138 my $log = $self->_get_logger();
139 $log->debug("fetch_rec($mfn) = ", dump($rec));
140
141 return $rec;
142 }
143
144 =head2 size
145
146 Return number of records in database
147
148 my $size = $ll_db->size;
149
150 =cut
151
152 sub size {
153 my $self = shift;
154 return $self->{size};
155 }
156
157 =head2 _to_hash
158
159 Return hash from row. Taken from L<Biblio::Isis>
160
161 my $rec = $ll_db->_to_hash(
162 mfn => $mfn;
163 $row
164 );
165
166 =cut
167
168 sub _to_hash {
169 my $self = shift;
170
171 my $arg = {@_};
172
173 my $log = $self->_get_logger();
174
175 my $hash_filter = $arg->{hash_filter};
176 my $mfn = $arg->{mfn} || $log->logconfess("need mfn in arguments");
177 my $row = $arg->{row} || $log->logconfess("need row in arguments");
178
179 # init record to include MFN as field 000
180 my $rec = { '000' => [ $mfn ] };
181
182 foreach my $f_nr (keys %{$row}) {
183 foreach my $l (@{$row->{$f_nr}}) {
184
185 # filter output
186 $l = $hash_filter->($l, $f_nr) if ($hash_filter);
187 next unless defined($l);
188
189 my $val;
190 my $r_sf; # repeatable subfields in this record
191
192 # has subfields?
193 if ($l =~ m/\^/) {
194 foreach my $t (split(/\^/,$l)) {
195 next if (! $t);
196 my ($sf,$v) = (substr($t,0,1), substr($t,1));
197 next unless (defined($v) && $v ne '');
198
199 if (ref( $val->{$sf} ) eq 'ARRAY') {
200
201 push @{ $val->{$sf} }, $v;
202
203 # record repeatable subfield it it's offset
204 push @{ $val->{subfields} }, ( $sf, $#{ $val->{$sf} } );
205 $r_sf->{$sf}++;
206
207 } elsif (defined( $val->{$sf} )) {
208
209 # convert scalar field to array
210 $val->{$sf} = [ $val->{$sf}, $v ];
211
212 push @{ $val->{subfields} }, ( $sf, 1 );
213 $r_sf->{$sf}++;
214
215 } else {
216 $val->{$sf} = $v;
217 push @{ $val->{subfields} }, ( $sf, 0 );
218 }
219 }
220 } else {
221 $val = $l;
222 }
223
224 push @{$rec->{$f_nr}}, $val;
225 }
226 }
227
228 return $rec;
229 }
230
231 =head1 AUTHOR
232
233 Dobrica Pavlinusic, C<< <dpavlin@rot13.org> >>
234
235 =head1 COPYRIGHT & LICENSE
236
237 Copyright 2007 Dobrica Pavlinusic, All Rights Reserved.
238
239 This program is free software; you can redistribute it and/or modify it
240 under the same terms as Perl itself.
241
242 =cut
243
244 1; # End of WebPAC::Input::DBF

  ViewVC Help
Powered by ViewVC 1.1.26