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) = @_;
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 (!exists($skip_computable{'basic'})) {
146 foreach my $cap_id ($mfhd->caption_link_ids('853')) {
147 my @holdings = $mfhd->holdings('863', $cap_id);
148 next unless scalar @holdings;
149 foreach (@holdings) {
150 push @$basic_holdings, $_->format();
153 if (!@$basic_holdings) { # no computed holdings found
154 $basic_holdings = $basic_holdings_add;
155 $basic_holdings_add = [];
157 } else { # textual are non additional, but primary
158 $basic_holdings = $basic_holdings_add;
159 $basic_holdings_add = [];
162 if (!exists($skip_computable{'supplement'})) {
163 foreach my $cap_id ($mfhd->caption_link_ids('854')) {
164 my @supplements = $mfhd->holdings('864', $cap_id);
165 next unless scalar @supplements;
166 foreach (@supplements) {
167 push @$supplement_holdings, $_->format();
170 if (!@$supplement_holdings) { # no computed holdings found
171 $supplement_holdings = $supplement_holdings_add;
172 $supplement_holdings_add = [];
174 } else { # textual are non additional, but primary
175 $supplement_holdings = $supplement_holdings_add;
176 $supplement_holdings_add = [];
179 if (!exists($skip_computable{'index'})) {
180 foreach my $cap_id ($mfhd->caption_link_ids('855')) {
181 my @indexes = $mfhd->holdings('865', $cap_id);
182 next unless scalar @indexes;
184 push @$index_holdings, $_->format();
187 if (!@$index_holdings) { # no computed holdings found
188 $index_holdings = $index_holdings_add;
189 $index_holdings_add = [];
191 } else { # textual are non additional, but primary
192 $index_holdings = $index_holdings_add;
193 $index_holdings_add = [];
196 # Laurentian extensions
197 foreach my $field ($marc->field('530')) {
198 my $online_stmt = $self->format_textual_holdings($field);
200 push @$online, $online_stmt;
204 foreach my $field ($marc->field('590')) {
205 my $missing_stmt = $self->format_textual_holdings($field);
207 push @$missing, $missing_stmt;
211 foreach my $field ($marc->field('591')) {
212 my $incomplete_stmt = $self->format_textual_holdings($field);
213 if ($incomplete_stmt) {
214 push @$incomplete, $incomplete_stmt;
219 $logger->error("MFHD statement parsing error: " . shift());
223 location => $location,
224 basic_holdings => $basic_holdings,
225 basic_holdings_add => $basic_holdings_add,
226 supplement_holdings => $supplement_holdings,
227 supplement_holdings_add => $supplement_holdings_add,
228 index_holdings => $index_holdings,
229 index_holdings_add => $index_holdings_add,
231 incomplete => $incomplete,
238 =item * init_holdings_virtual_record()
242 Initialize the serial virtual record (svr) instance
246 sub init_holdings_virtual_record {
247 my $record = Fieldmapper::serial::virtual_record->new;
250 $record->owning_lib();
251 $record->basic_holdings([]);
252 $record->basic_holdings_add([]);
253 $record->supplement_holdings([]);
254 $record->supplement_holdings_add([]);
255 $record->index_holdings([]);
256 $record->index_holdings_add([]);
258 $record->missing([]);
259 $record->incomplete([]);
265 =item * init_holdings_virtual_record($mfhd)
269 Given an MFHD record, return a populated svr instance
274 my ($self, $id, $mfhd, $owning_lib) = @_;
280 my $record = init_holdings_virtual_record();
281 my $holdings = $self->mfhd_to_hash($mfhd);
283 $record->sre_id($id);
284 $record->owning_lib($owning_lib);
290 $record->location($holdings->{location});
291 $record->basic_holdings($holdings->{basic_holdings});
292 $record->basic_holdings_add($holdings->{basic_holdings_add});
293 $record->supplement_holdings($holdings->{supplement_holdings});
294 $record->supplement_holdings_add($holdings->{supplement_holdings_add});
295 $record->index_holdings($holdings->{index_holdings});
296 $record->index_holdings_add($holdings->{index_holdings_add});
297 $record->online($holdings->{online});
298 $record->missing($holdings->{missing});
299 $record->incomplete($holdings->{incomplete});
306 # vim: ts=4:sw=4:noet