--- trunk/lib/WebPAC/Normalize.pm 2006/07/04 11:08:43 579 +++ trunk/lib/WebPAC/Normalize.pm 2006/08/25 12:31:01 618 @@ -9,6 +9,7 @@ marc marc_indicators marc_repeatable_subfield marc_compose marc_leader marc_duplicate marc_remove + marc_original_order rec1 rec2 rec regex prefix suffix surround @@ -35,11 +36,11 @@ =head1 VERSION -Version 0.11 +Version 0.16 =cut -our $VERSION = '0.11'; +our $VERSION = '0.16'; =head1 SYNOPSIS @@ -69,6 +70,7 @@ row => $row, rules => $normalize_pl_config, marc_encoding => 'utf-8', + config => $config, ); Options C, C, C and C are mandatory while all @@ -90,6 +92,7 @@ no strict 'subs'; _set_lookup( $arg->{lookup} ); _set_rec( $arg->{row} ); + _set_config( $arg->{config} ); _clean_ds( %{ $arg } ); eval "$arg->{rules}"; die "error evaling $arg->{rules}: $@\n" if ($@); @@ -111,6 +114,34 @@ $rec = shift or die "no record hash"; } +=head2 _set_config + +Set current config hash + + _set_config( $config ); + +Magic keys are: + +=over 4 + +=item _ + +Code of current database + +=item _mfn + +Current MFN + +=back + +=cut + +my $config; + +sub _set_config { + $config = shift; +} + =head2 _get_ds Return hash formatted as data structure @@ -495,6 +526,9 @@ 'c', rec('200','c') ); +If you specify C<+> for subfield, value will be appended +to previous defined subfield. + =cut sub marc_compose { @@ -504,17 +538,23 @@ my ($i1,$i2) = defined($marc_indicators->{$f}) ? @{ $marc_indicators->{$f} } : (' ',' '); my $m = [ $f, $i1, $i2 ]; + warn "### marc_compose input subfields = ", dump(@_),$/ if ($debug > 2); + while (@_) { my $sf = shift or die "marc_compose $f needs subfield"; my $v = shift; next unless (defined($v) && $v !~ /^\s*$/); from_to($v, 'iso-8859-2', $marc_encoding) if ($marc_encoding); - push @$m, ( $sf, $v ); warn "## ++ marc_compose($f,$sf,$v) ", dump( $m ),$/ if ($debug > 1); + if ($sf ne '+') { + push @$m, ( $sf, $v ); + } else { + $m->[ $#$m ] .= $v; + } } - warn "## marc_compose(d) ", dump( $m ),$/ if ($debug > 1); + warn "## marc_compose current marc = ", dump( $m ),$/ if ($debug > 1); push @{ $marc_record->[ $marc_record_offset ] }, $m if ($#{$m} > 2); } @@ -602,6 +642,77 @@ warn "## full marc_record = ", dump( @{ $marc_record }), $/ if ($debug > 1); } +=head2 marc_original_order + +Copy all subfields preserving original order to marc field. + + marc_original_order( marc_field_number, original_input_field_number ); + +Please note that field numbers are consistent with other commands (marc +field number first), but somewhat counter-intuitive (destination and then +source). + +You might want to use this command if you are just renaming subfields or +using pre-processing modify_record in C and don't need any +post-processing or want to preserve order of original subfields. + + +=cut + +sub marc_original_order { + + my ($to, $from) = @_; + die "marc_original_order needs from and to fields\n" unless ($from && $to); + + return unless defined($rec->{$from}); + + my $r = $rec->{$from}; + die "record field $from isn't array\n" unless (ref($r) eq 'ARRAY'); + + my ($i1,$i2) = defined($marc_indicators->{$to}) ? @{ $marc_indicators->{$to} } : (' ',' '); + warn "## marc_original_order($to,$from) source = ", dump( $r ),$/ if ($debug > 1); + + foreach my $d (@$r) { + + if (! defined($d->{subfields}) && ref($d->{subfields}) ne 'ARRAY') { + warn "# marc_original_order($to,$from): field $from doesn't have subfields specification\n"; + next; + } + + my @sfs = @{ $d->{subfields} }; + + die "field $from doesn't have even number of subfields specifications\n" unless($#sfs % 2 == 1); + + warn "#--> d: ",dump($d), "\n#--> sfs: ",dump(@sfs),$/ if ($debug > 2); + + my $m = [ $to, $i1, $i2 ]; + + while (my $sf = shift @sfs) { + + warn "#--> sf: ",dump($sf), $/ if ($debug > 2); + my $offset = shift @sfs; + die "corrupted sufields specification for field $from\n" unless defined($offset); + + my $v; + if (ref($d->{$sf}) eq 'ARRAY') { + $v = $d->{$sf}->[$offset] if (defined($d->{$sf}->[$offset])); + } elsif ($offset == 0) { + $v = $d->{$sf}; + } else { + die "field $from subfield '$sf' need occurence $offset which doesn't exist", dump($d->{$sf}); + } + push @$m, ( $sf, $v ) if (defined($v)); + } + + if ($#{$m} > 2) { + push @{ $marc_record->[ $marc_record_offset ] }, $m; + } + } + + warn "## marc_record = ", dump( $marc_record ),$/ if ($debug > 1); +} + + =head1 Functions to extract data from input This function should be used inside functions to create C described @@ -647,7 +758,14 @@ my $f = shift; return unless (defined($rec && $rec->{$f})); my $sf = shift; - return map { $_->{$sf} } grep { ref($_) eq 'HASH' && $_->{$sf} } @{ $rec->{$f} }; + warn "rec2($f,$sf) = ", dump( $rec->{$f} ), $/ if ($debug > 1); + return map { + if (ref($_->{$sf}) eq 'ARRAY') { + @{ $_->{$sf} }; + } else { + $_->{$sf}; + } + } grep { ref($_) eq 'HASH' && $_->{$sf} } @{ $rec->{$f} }; } =head2 rec @@ -660,10 +778,16 @@ =cut sub rec { + my @out; if ($#_ == 0) { - return rec1(@_); + @out = rec1(@_); } elsif ($#_ == 1) { - return rec2(@_); + @out = rec2(@_); + } + if (@out) { + return @out; + } else { + return ''; } } @@ -696,7 +820,7 @@ =cut sub prefix { - my $p = shift or die "prefix needs string as first argument"; + my $p = shift or return; return map { $p . $_ } grep { defined($_) } @_; } @@ -759,6 +883,78 @@ } } +=head2 config + +Consult config values stored in C + + # return database code (key under databases in yaml) + $database_code = config(); # use _ from hash + $database_name = config('name'); + $database_input_name = config('input name'); + $tag = config('input normalize tag'); + +Up to three levels are supported. + +=cut + +sub config { + return unless ($config); + + my $p = shift; + + $p ||= ''; + + my $v; + + warn "### getting config($p)\n" if ($debug > 1); + + my @p = split(/\s+/,$p); + if ($#p < 0) { + $v = $config->{ '_' }; # special, database code + } else { + + my $c = dclone( $config ); + + foreach my $k (@p) { + warn "### k: $k c = ",dump($c),$/ if ($debug > 1); + if (ref($c) eq 'ARRAY') { + $c = shift @$c; + warn "config($p) taking first occurence of '$k', probably not what you wanted!\n"; + last; + } + + if (! defined($c->{$k}) ) { + $c = undef; + last; + } else { + $c = $c->{$k}; + } + } + $v = $c if ($c); + + } + + warn "## config( '$p' ) = ",dump( $v ),$/ if ($v && $debug); + warn "config( '$p' ) is empty\n" if (! $v); + + return $v; +} + +=head2 id + +Returns unique id of this record + + $id = id(); + +Returns C<42/2> for 2nd occurence of MFN 42. + +=cut + +sub id { + my $mfn = $config->{_mfn} || die "no _mfn in config data"; + return $mfn . $#{$marc_record} ? $#{$marc_record} + 1 : ''; +} + =head2 join_with Joins walues with some delimiter @@ -769,7 +965,10 @@ sub join_with { my $d = shift; - return join($d, grep { defined($_) && $_ ne '' } @_); + warn "### join_with('$d',",dump(@_),")\n" if ($debug > 2); + my $v = join($d, grep { defined($_) && $_ ne '' } @_); + return '' unless defined($v); + return $v; } =head2 split_rec_on @@ -797,7 +996,7 @@ my $v = shift @r; warn "### first rec($fld,$sf) = ",dump($v),$/ if ($debug > 2); - return '' if( ! defined($v) || $v =~ /^\s*$/); + return '' if ( ! defined($v) || $v =~ /^\s*$/); my @s = split( $regex, $v ); warn "## split_rec_on($fld,$sf,$regex,$part) = ",dump(@s),$/ if ($debug > 1);