sort leader offsets to support marc_clone
[webpac2] / lib / WebPAC / Output / MARC.pm
index 7d0ea31..89e38fe 100644 (file)
@@ -5,7 +5,7 @@ use strict;
 
 use base qw/WebPAC::Common/;
 
-use MARC::Record 2.0;  # need 2.0 for utf-8 encoding see marcpm.sf.net
+use MARC::Record;
 use MARC::Lint;
 use Data::Dump qw/dump/;
 
@@ -15,11 +15,11 @@ WebPAC::Output::MARC - Create MARC records from C<marc_*> normalisation rules
 
 =head1 VERSION
 
-Version 0.01
+Version 0.04
 
 =cut
 
-our $VERSION = '0.01';
+our $VERSION = '0.04';
 
 =head1 SYNOPSIS
 
@@ -33,7 +33,7 @@ L<WebPAC::Normalize>.
 
   my $marc = new WebPAC::Output::MARC(
        path => '/path/to/output.marc',
-       encoding => 'utf-8',
+       marc_encoding => 'utf-8',
        lint => 1,
        dump => 0,
   )
@@ -52,17 +52,18 @@ sub new {
                        $log->warn("Can't create MARC::Lint object, linting is disabled");
        }
 
+       $self->{marc_encoding} ||= 'utf-8';
+
        if (my $path = $self->{path}) {
                open($self->{fh}, '>', $path) ||
                        $log->logdie("can't open MARC output $path: $!");
+               binmode($self->{fh}, ':utf8');
 
-               $log->info("Creating MARC export file $path", $self->{lint} ? ' (with lint)' : '', "\n");
+               $log->info("Creating MARC export file $path", $self->{lint} ? ' (with lint)' : '', " encoding ", $self->{marc_encoding}, "\n");
        } else {
                $log->logconfess("new called without path");
        }
 
-       $self->{encoding} ||= 'utf-8';
-
        $self ? return $self : return undef;
 }
 
@@ -71,9 +72,13 @@ sub new {
   $marc->add(
        id => $mfn,
        fields => WebPAC::Normalize::_get_marc_fields(),
-       leader => WebPAC::Normalize::marc_leader(),
+       leader => WebPAC::Normalize::_get_marc_leader(),
+       row => $row,
   );
 
+C<row> is optional parametar which is used when dumping original row to
+error log.
+
 =cut
 
 sub add {
@@ -87,20 +92,37 @@ sub add {
                unless ($arg->{fields} && defined $arg->{id});
 
        my $marc = new MARC::Record;
-       $marc->encoding( $self->{encoding} );
+       $marc->encoding( $self->{marc_encoding} );
 
-       my $id = $self->{id};
+       my $id = $arg->{id};
 
        $log->logconfess("fields isn't array") unless (ref($arg->{fields}) eq 'ARRAY');
 
-       $marc->add_fields( @{ $arg->{fields} } );
+       my $fields = $arg->{fields};
+
+       $log->debug("original fields = ", sub { dump( $fields ) });
+
+       # recode fields to marc_encoding
+       foreach my $j ( 0 .. $#$fields ) {
+               foreach my $i ( 0 .. ( ( $#{$fields->[$j]} - 3 ) / 2 ) ) {
+                       my $f = $fields->[$j]->[ ($i * 2) + 4 ];
+                       $fields->[$j]->[ ($i * 2) + 4 ] = $f;
+               }
+       }
+
+       # sort fields
+       @$fields = sort { $a->[0] <=> $b->[0] } @$fields;
+
+       $log->debug("recode fields = ", sub { dump( $fields ) });
+
+       $marc->add_fields( @$fields );
 
        # tweak leader
        if (my $new_l = $arg->{leader}) {
 
                my $leader = $marc->leader;
 
-               foreach my $o ( keys %$new_l ) {
+               foreach my $o ( sort { $a <=> $b } keys %$new_l ) {
                        my $insert = $new_l->{$o};
                        $leader = substr($leader, 0, $o) .
                                $insert . substr($leader, $o+length($insert));
@@ -110,18 +132,21 @@ sub add {
 
        if ($self->{lint}) {
                $self->{lint}->check_record( $marc );
-               my $err = join( "\n", $self->{lint}->warnings );
-               $log->error("MARC lint detected warning on record $id\n",
-                       "<<<<< Original imput row:\n",dump($arg->{row}), "\n",
-                       ">>>>> Normalized MARC row: leader: [", $marc->leader(), "]\n", dump( $arg->{fields} ), "\n",
-                       "!!!!! MARC lint warnings:\n",$err,"\n"
-               ) if ($err);
+               my @w = $self->{lint}->warnings;
+               if (@w) {
+                       $log->error("MARC lint detected warning on record $id\n",
+                               "<<<<< Original input row:\n",dump($arg->{row}), "\n",
+                               ">>>>> Normalized MARC row: leader: [", $marc->leader(), "]\n", dump( $fields ), "\n",
+                               "!!!!! MARC lint warnings:\n",join("\n",@w),"\n"
+                       );
+                       map { $self->{_marc_lint_warnings}->{$_}++ } @w;
+               }
        }
 
        if ($self->{dump}) {
                $log->info("MARC record on record $id\n",
-                       "<<<<< Original imput row:\n",dump($self->{row}), "\n",
-                       ">>>>> Normalized MARC row: leader: [", $marc->leader(), "]\n", dump( $arg->{fields} ), "\n",
+                       "<<<<< Original imput row:\n",dump($arg->{row}), "\n",
+                       ">>>>> Normalized MARC row: leader: [", $marc->leader(), "]\n", dump( $fields ), "\n",
                );
        }
 
@@ -135,12 +160,25 @@ Close MARC output file
 
   $marc->finish;
 
+It will also dump MARC lint warnings summary if called with C<lint>.
+
 =cut
 
 sub finish {
        my $self = shift;
 
-       close( $self->{fh} ) or $self->_get_logger->logdie("can't close ", $self->{path}, ": $!");
+       my $log = $self->get_logger;
+
+       close( $self->{fh} ) or $log->logdie("can't close ", $self->{path}, ": $!");
+
+       if (my $w = $self->{_marc_lint_warnings}) {
+               $log->error("MARC lint warnings summary:\n",
+                       join ("\n",
+                               map { $w->{$_} . "\t" . $_ }
+                               sort { $w->{$b} <=> $w->{$a} } keys %$w
+                       )
+               );
+       }
 }
 
 =head1 AUTHOR