1 package OpenILS::Utils::MFHDParser;
5 use OpenSRF::EX qw/:try/;
6 use Time::HiRes qw(time);
7 use OpenILS::Utils::Fieldmapper;
8 use OpenSRF::Utils::SettingsClient;
9 use OpenSRF::Utils::Logger qw/$logger/;
11 use OpenILS::Utils::MFHD;
12 use MARC::File::XML (BinaryEncoding => 'utf8');
15 sub new { return bless({}, shift()); }
21 =item * format_textual_holdings($field)
25 Returns concatenated subfields $a with $z for textual holdings (866-868)
29 sub format_textual_holdings {
30 my ($self, $field) = @_;
34 $holdings = $field->subfield('a');
39 $public_note = $field->subfield('z');
41 return "$holdings -- $public_note";
48 =item * mfhd_to_hash($mfhd_xml)
52 Returns a Perl hash containing fields of interest from the MFHD record
57 my ($self, $mfhd_xml, $skip_all_computable) = @_;
63 my $basic_holdings = [];
64 my $supplement_holdings = [];
65 my $index_holdings = [];
66 my $basic_holdings_add = [];
67 my $supplement_holdings_add = [];
68 my $index_holdings_add = [];
69 my $online = []; # Laurentian extension to MFHD standard
70 my $missing = []; # Laurentian extension to MFHD standard
71 my $incomplete = []; # Laurentian extension to MFHD standard
74 $marc = MARC::Record->new_from_xml($mfhd_xml);
77 $logger->error("Failed to convert MFHD XML to MARC: " . shift());
78 $logger->error("Failed MFHD XML: $mfhd_xml");
86 $mfhd = MFHD->new($marc);
89 $logger->error("Failed to parse MFHD: " . shift());
90 $logger->error("Failed MFHD XML: $mfhd_xml");
98 foreach my $field ($marc->field('852')) {
99 foreach my $subfield_ref ($field->subfields) {
100 my ($subfield, $data) = @$subfield_ref;
101 $location .= $data . " -- ";
106 $logger->error("MFHD location parsing error: " . shift());
109 $location =~ s/ -- $//;
111 # TODO: for now, we will assume that textual holdings are in addition to the
112 # computable holdings (that is, they have link IDs greater than the 85X fields)
113 # or that they fully replace the computable holdings (checking for link ID '0').
114 # Eventually this may be handled better by format_holdings() in MFHD.pm
117 foreach my $field ($marc->field('866')) {
118 my $textual_holdings = $self->format_textual_holdings($field);
119 if ($textual_holdings) {
120 push @$basic_holdings_add, $textual_holdings;
121 if ($field->subfield('8') eq '0') {
122 $skip_computable{'basic'} = 1; # link ID 0 trumps computable fields
126 foreach my $field ($marc->field('867')) {
127 my $textual_holdings = $self->format_textual_holdings($field);
128 if ($textual_holdings) {
129 push @$supplement_holdings_add, $textual_holdings;
130 if ($field->subfield('8') eq '0') {
131 $skip_computable{'supplement'} = 1; # link ID 0 trumps computable fields
135 foreach my $field ($marc->field('868')) {
136 my $textual_holdings = $self->format_textual_holdings($field);
137 if ($textual_holdings) {
138 push @$index_holdings_add, $textual_holdings;
139 if ($field->subfield('8') eq '0') {
140 $skip_computable{'index'} = 1; # link ID 0 trumps computable fields
145 if (!$skip_all_computable) {
146 if (!exists($skip_computable{'basic'})) {
147 foreach my $cap_id ($mfhd->caption_link_ids('853')) {
148 my @holdings = $mfhd->holdings('863', $cap_id);
149 next unless scalar @holdings;
150 foreach (@holdings) {
151 push @$basic_holdings, $_->format();
154 if (!@$basic_holdings) { # no computed holdings found
155 $basic_holdings = $basic_holdings_add;
156 $basic_holdings_add = [];
158 } else { # textual are non additional, but primary
159 $basic_holdings = $basic_holdings_add;
160 $basic_holdings_add = [];
163 if (!exists($skip_computable{'supplement'})) {
164 foreach my $cap_id ($mfhd->caption_link_ids('854')) {
165 my @supplements = $mfhd->holdings('864', $cap_id);
166 next unless scalar @supplements;
167 foreach (@supplements) {
168 push @$supplement_holdings, $_->format();
171 if (!@$supplement_holdings) { # no computed holdings found
172 $supplement_holdings = $supplement_holdings_add;
173 $supplement_holdings_add = [];
175 } else { # textual are non additional, but primary
176 $supplement_holdings = $supplement_holdings_add;
177 $supplement_holdings_add = [];
180 if (!exists($skip_computable{'index'})) {
181 foreach my $cap_id ($mfhd->caption_link_ids('855')) {
182 my @indexes = $mfhd->holdings('865', $cap_id);
183 next unless scalar @indexes;
185 push @$index_holdings, $_->format();
188 if (!@$index_holdings) { # no computed holdings found
189 $index_holdings = $index_holdings_add;
190 $index_holdings_add = [];
192 } else { # textual are non additional, but primary
193 $index_holdings = $index_holdings_add;
194 $index_holdings_add = [];
198 # Laurentian extensions
199 foreach my $field ($marc->field('530')) {
200 my $online_stmt = $self->format_textual_holdings($field);
202 push @$online, $online_stmt;
206 foreach my $field ($marc->field('590')) {
207 my $missing_stmt = $self->format_textual_holdings($field);
209 push @$missing, $missing_stmt;
213 foreach my $field ($marc->field('591')) {
214 my $incomplete_stmt = $self->format_textual_holdings($field);
215 if ($incomplete_stmt) {
216 push @$incomplete, $incomplete_stmt;
221 $logger->error("MFHD statement parsing error: " . shift());
225 location => $location,
226 basic_holdings => $basic_holdings,
227 basic_holdings_add => $basic_holdings_add,
228 supplement_holdings => $supplement_holdings,
229 supplement_holdings_add => $supplement_holdings_add,
230 index_holdings => $index_holdings,
231 index_holdings_add => $index_holdings_add,
233 incomplete => $incomplete,
240 =item * init_holdings_virtual_record()
244 Initialize the serial virtual record (svr) instance
248 sub init_holdings_virtual_record {
249 my $record = Fieldmapper::serial::virtual_record->new;
252 $record->owning_lib();
253 $record->basic_holdings([]);
254 $record->basic_holdings_add([]);
255 $record->supplement_holdings([]);
256 $record->supplement_holdings_add([]);
257 $record->index_holdings([]);
258 $record->index_holdings_add([]);
260 $record->missing([]);
261 $record->incomplete([]);
267 =item * init_holdings_virtual_record($mfhd)
271 Given an MFHD record, return a populated svr instance
276 my ($self, $id, $mfhd, $owning_lib, $skip_all_computable) = @_;
282 my $record = init_holdings_virtual_record();
283 my $holdings = $self->mfhd_to_hash($mfhd, $skip_all_computable);
285 $record->sre_id($id);
286 $record->owning_lib($owning_lib);
292 $record->location($holdings->{location});
293 $record->basic_holdings($holdings->{basic_holdings});
294 $record->basic_holdings_add($holdings->{basic_holdings_add});
295 $record->supplement_holdings($holdings->{supplement_holdings});
296 $record->supplement_holdings_add($holdings->{supplement_holdings_add});
297 $record->index_holdings($holdings->{index_holdings});
298 $record->index_holdings_add($holdings->{index_holdings_add});
299 $record->online($holdings->{online});
300 $record->missing($holdings->{missing});
301 $record->incomplete($holdings->{incomplete});
308 # vim: ts=4:sw=4:noet