File Coverage

blib/lib/MARC/Utils/MARC2MARC_in_JSON.pm
Criterion Covered Total %
statement 100 101 99.0
branch 31 36 86.1
condition 4 6 66.6
subroutine 13 13 100.0
pod 0 3 0.0
total 148 159 93.0


line stmt bran cond sub pod time code
1             #---------------------------------------------------------------------
2             package MARC::Utils::MARC2MARC_in_JSON;
3              
4 1     1   34561 use 5.008002;
  1         4  
  1         209  
5 1     1   8 use strict;
  1         11  
  1         40  
6 1     1   7 use warnings;
  1         6  
  1         40  
7 1     1   5 use Carp;
  1         2  
  1         192  
8              
9             our $VERSION = '0.05';
10              
11             our (@ISA, @EXPORT_OK);
12             BEGIN {
13 1     1   6 require Exporter;
14 1         24 @ISA = qw(Exporter);
15 1         23 @EXPORT_OK = qw( marc2marc_in_json marc_in_json2marc each_record );
16             }
17              
18 1     1   1294 use MARC::Record;
  1         13471  
  1         66  
19 1     1   1786 use JSON; # decode_json()
  1         28398  
  1         8  
20              
21             #---------------------------------------------------------------------
22             sub marc2marc_in_json {
23 1     1 0 1455 my( $marc_record ) = @_;
24              
25 1         3 my %marc_in_json;
26              
27 1         7 for my $leader ( $marc_record->leader() ) {
28 1         10 $marc_in_json{'leader'} = $leader;
29             }
30              
31 1         7 for my $field ( $marc_record->fields() ) {
32              
33 27         122 my $ftag = $field->tag();
34              
35 27 100       151 if( $field->is_control_field() ) {
36 4         22 push @{$marc_in_json{'fields'}}, { $ftag => $field->data() };
  4         15  
37             }
38              
39             else {
40 23         104 my $fdata;
41              
42 23         34 for my $i ( 1, 2 ) {
43 46         387 $fdata->{"ind$i"} = $field->indicator( $i )
44             }
45              
46 23         273 for my $subfield ( $field->subfields ) {
47 44         401 push @{$fdata->{'subfields'}}, { $subfield->[0] => $subfield->[1] };
  44         183  
48             }
49              
50 23         52 push @{$marc_in_json{'fields'}}, { $ftag => $fdata };
  23         101  
51             }
52             }
53              
54 1         6 \%marc_in_json; # returned
55             }
56              
57             #---------------------------------------------------------------------
58             sub marc_in_json2marc {
59 2     2 0 49 my( $marc_in_json ) = @_;
60              
61 2         16 my $marc_record = MARC::Record->new();
62              
63 2         26 for my $leader ( $marc_in_json->{'leader'} ) {
64 2         8 $marc_record->leader( $leader );
65             }
66              
67 2         32 for my $field ( @{$marc_in_json->{'fields'}} ) {
  2         7  
68 54         2641 my( $ftag, $fdata ) = %$field;
69              
70 54 100       107 if( ref $fdata ) {
71 46         48 my @subfields;
72 46         49 for my $subfield ( @{$fdata->{'subfields'}} ) {
  46         92  
73 88         171 my( $sftag, $sfdata ) = %$subfield;
74 88         184 push @subfields, $sftag, $sfdata;
75             }
76 46         173 $marc_record->append_fields( MARC::Field->new(
77             $ftag, $fdata->{'ind1'}, $fdata->{'ind2'}, @subfields ) );
78             }
79              
80             # control field
81             else {
82 8         32 $marc_record->append_fields( MARC::Field->new( $ftag, $fdata ) );
83             }
84             }
85              
86 2         99 $marc_record; #returned
87             }
88              
89             #---------------------------------------------------------------------
90             sub each_record {
91 10     10 0 8073 my( $filename, $declared_filetype ) = @_;
92            
93 10 50       553 open my $fh, '<', $filename or croak "Can't open $filename: $!";
94              
95             # examine beginning of file to determine its type
96              
97 10         196 my $first_line = <$fh>;
98 10         13 my( $filetype, $recsep );
99              
100 10         26 for( $first_line ) {
101 10 100       58 if( /^\[/ ) {
    100          
102 4         5 $filetype = 'collection';
103 4 50       19 if( /^\[\n$/ ) {
104 4         7 my $second_line = <$fh>;
105 4 100       16 if( $second_line eq "\n" ) {
106 2         4 $filetype = 'collection-delimited';
107 2         6 $recsep = "\n\n";
108             }
109             }
110             }
111             elsif( /^{/ ) #vi}
112             {
113 2 100 66     15 if( $declared_filetype and
114             $declared_filetype eq 'ndj' ) { # newline delimited json
115 1         2 $filetype = $declared_filetype;
116 1         3 $recsep = "\n";
117             }
118             else {
119 1         3 $filetype = 'object';
120             }
121             }
122             else {
123 4         8 $filetype = 'delimited';
124 4         14 $recsep = "\n$_";
125             }
126             }
127              
128 10 50 66     46 croak "File doesn't match file type: $filename, $declared_filetype vs. $filetype"
129             if $declared_filetype and $declared_filetype ne $filetype;
130              
131 10 100       67 if( $filetype =~ /^object|collection$/ ) {
    100          
    50          
132              
133 3         29 seek $fh, 0, 0; # rewind to top
134 3         35 local $/;
135              
136 3         2044 my $json_items = decode_json( <$fh> ); # slurp
137 3 100       15 $json_items = [$json_items] if $filetype eq 'object';
138 3         5 my $index = 0;
139              
140             # "get_next" closure
141             return sub {
142 14 100   14   721 return if $index > $#$json_items;
143 11         29 return $json_items->[ $index ++ ];
144 3         69 };
145              
146             }
147              
148             elsif( $filetype =~ /delimited$/ ) {
149              
150             # "get_next" closure
151             return sub {
152 36     36   2931 local $/ = $recsep;
153 36         1451 my $text = <$fh>;
154 36 100       138 return unless defined $text;
155 32 100       197 return unless $text =~ /^\s*{/;
156 30         334 chomp $text;
157 30         1272 $text =~ s/,\s*$//;
158 30         4131 return decode_json $text;
159 6         41 };
160              
161             }
162              
163             elsif( $filetype eq 'ndj' ) {
164              
165 1         9 seek $fh, 0, 0; # rewind to top
166              
167             # "get_next" closure
168             return sub {
169 6     6   439 local $/ = $recsep;
170 6         83 my $text = <$fh>;
171 6 100       16 return unless defined $text;
172 5 50       22 return unless $text =~ /^\s*{/;
173 5         49 chomp $text;
174 5         128 $text =~ s/,\s*$//; # just in case
175 5         494 return decode_json $text;
176 1         8 };
177              
178             }
179              
180             else {
181 0           croak "Unrecognized file type: $filename";
182             }
183              
184             }
185              
186             1;
187              
188             __END__