3 # Copyright 2006 (C) LibLime
4 # Joshua Ferraro <jmf@liblime.com>
6 # This file is part of Koha.
8 # Koha is free software; you can redistribute it and/or modify it under the
9 # terms of the GNU General Public License as published by the Free Software
10 # Foundation; either version 2 of the License, or (at your option) any later
13 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
14 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License along with
18 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
19 # Suite 330, Boston, MA 02111-1307 USA
23 use strict; use warnings; #FIXME: turn off warnings before release
25 # please specify in which methods a given module is used
26 use MARC::Record; #marc2marcxml, marcxml2marc, html2marc, changeEncoding
27 use MARC::File::XML; #marc2marcxml, marcxml2marc, html2marcxml, changeEncoding
29 use vars qw($VERSION @ISA @EXPORT);
31 # set the version for version checking
32 $VERSION = do { my @v = '$Revision$' =~ /\d+/g;
33 shift(@v) . "." . join("_", map {sprintf "%03d", $_ } @v); };
37 # only export API methods
49 C4::Record - MARC, MARCXML, XML, etc. Record Management Functions and API
53 New in Koha 3.x. This module handles all record-related management functions.
59 my $marcxml = marc2marcxml($marc,$encoding,$flavour);
61 returns an XML scalar variable
63 C<$marc> a MARC::Record object or binary MARC record
65 C<$encoding> UTF-8 or MARC-8 [UTF-8}
67 C<$flavour> MARC21 or UNIMARC
72 my ($marc,$encoding,$flavour) = @_;
73 unless($encoding) {$encoding = "UTF-8"};
74 unless($flavour) {$flavour = C4::Context->preference("TemplateEncoding")};
75 #FIXME: add error handling
76 my $marcxml = $record->as_xml_record($marc,$encoding,$flavour);
82 my $marc = marcxml2marc($marcxml,$encoding,$flavour);
84 returns a binary MARC scalar variable
86 C<$marcxml> a MARCXML record
88 C<$encoding> UTF-8 or MARC-8 [UTF-8]
90 C<$flavour> MARC21 or UNIMARC
95 my ($marcxml,$encoding,$flavour) = @_;
96 unless($encoding) {$encoding = "UTF-8"};
97 unless($flavour) {$flavour = C4::Context->preference("TemplateEncoding")};
98 #FIXME: add error handling
99 my $marc = $marcxml->new_from_xml($record,$encoding,$flavour);
105 my $marcxml = html2marcxml($tags,$subfields,$values,$indicator,$ind_tag);
107 returns a MARCXML scalar variable
109 this is used in addbiblio.pl and additem.pl to build the MARCXML record from
112 FIXME: this could use some better code documentation
117 my ($tags,$subfields,$values,$indicator,$ind_tag) = @_;
118 # add the header info
119 my $marcxml= MARC::File::XML::header(C4::Context->preference('TemplateEncoding'),C4::Context->preference('marcflavour'));
121 # some flags used to figure out where in the record we are
127 # handle characters that would cause the parser to choke FIXME: is there a more elegant solution?
128 for (my $i=0;$i<=@$tags;$i++){
129 @$values[$i] =~ s/&/&/g;
130 @$values[$i] =~ s/</</g;
131 @$values[$i] =~ s/>/>/g;
132 @$values[$i] =~ s/"/"/g;
133 @$values[$i] =~ s/'/'/g;
135 if ((@$tags[$i] ne $prevtag)){
136 $j++ unless (@$tags[$i] eq "");
137 #warn "IND:".substr(@$indicator[$j],0,1).substr(@$indicator[$j],1,1)." ".@$tags[$i];
139 $marcxml.="</datafield>\n";
140 if ((@$tags[$i] > 10) && (@$values[$i] ne "")){
141 my $ind1 = substr(@$indicator[$j],0,1);
142 my $ind2 = substr(@$indicator[$j],1,1);
143 $marcxml.="<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
144 $marcxml.="<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
150 if (@$values[$i] ne "") {
152 if (@$tags[$i] eq "000") {
153 $marcxml.="<leader>@$values[$i]</leader>\n";
155 # rest of the fixed fields
156 } elsif (@$tags[$i] < 010) { #FIXME: <10 was the way it was, there might even be a better way
157 $marcxml.="<controlfield tag=\"@$tags[$i]\">@$values[$i]</controlfield>\n";
160 my $ind1 = substr(@$indicator[$j],0,1);
161 my $ind2 = substr(@$indicator[$j],1,1);
162 $marcxml.="<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
163 $marcxml.="<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
168 } else { # @$tags[$i] eq $prevtag
169 if (@$values[$i] eq "") {
172 my $ind1 = substr(@$indicator[$j],0,1);
173 my $ind2 = substr(@$indicator[$j],1,1);
174 $marcxml.="<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
177 $marcxml.="<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
180 $prevtag = @$tags[$i];
182 $marcxml.= MARC::File::XML::footer();
189 Probably best to avoid using this ... it has some rather striking problems:
191 * saves blank subfields
192 * subfield order is hardcoded to always start
193 with 'a' for repeatable tags (because it is hardcoded in the
195 * only possible to specify one set of indicators for each set of
196 tags (ie, one for all the 650s). (because they were stored in a
197 hash with the tag as the key).
198 * the underlying routines didn't support subfield
199 reordering or subfield repeatability.
201 I've left it in here because it could be useful if someone took the time to
207 my ($dbh,$rtags,$rsubfields,$rvalues,%indicators) = @_;
209 my $record = MARC::Record->new();
210 # my %subfieldlist=();
211 my $prevvalue; # if tag <10
212 my $field; # if tag >=10
213 for (my $i=0; $i< @$rtags; $i++) {
214 # rebuild MARC::Record
215 # warn "0=>".@$rtags[$i].@$rsubfields[$i]." = ".@$rvalues[$i].": ";
216 if (@$rtags[$i] ne $prevtag) {
219 if (($prevtag ne '000') && ($prevvalue ne "")) {
220 $record->add_fields((sprintf "%03s",$prevtag),$prevvalue);
221 } elsif ($prevvalue ne ""){
222 $record->leader($prevvalue);
226 if (($field) && ($field ne "")) {
227 $record->add_fields($field);
230 $indicators{@$rtags[$i]}.=' ';
231 # skip blank tags, I hope this works
232 if (@$rtags[$i] eq ''){
233 $prevtag = @$rtags[$i];
237 if (@$rtags[$i] <10) {
238 $prevvalue= @$rvalues[$i];
242 if (@$rvalues[$i] eq "") {
245 $field = MARC::Field->new( (sprintf "%03s",@$rtags[$i]), substr($indicators{@$rtags[$i]},0,1),substr($indicators{@$rtags[$i]},1,1), @$rsubfields[$i] => @$rvalues[$i]);
247 # warn "1=>".@$rtags[$i].@$rsubfields[$i]." = ".@$rvalues[$i].": ".$field->as_formatted;
249 $prevtag = @$rtags[$i];
251 if (@$rtags[$i] <10) {
252 $prevvalue=@$rvalues[$i];
254 if (length(@$rvalues[$i])>0) {
255 $field->add_subfields(@$rsubfields[$i] => @$rvalues[$i]);
256 # warn "2=>".@$rtags[$i].@$rsubfields[$i]." = ".@$rvalues[$i].": ".$field->as_formatted;
259 $prevtag= @$rtags[$i];
263 # the last has not been included inside the loop... do it now !
265 #warn Dumper($field->{_subfields});
266 $record->add_fields($field) if (($field) && $field ne "");
267 #warn "HTML2MARC=".$record->as_formatted;
271 =head2 changeEncoding
273 $newrecord = changeEncoding($record,$format,$flavour,$toencoding,$fromencoding);
275 changes the encoding of a record
277 <C$record the record itself can be in ISO2709, a MARC::Record object, or MARCXML for now (required)
279 <C$format MARC or MARCXML (required for now, eventually it will attempt to guess)
281 <C$flavour MARC21 or UNIMARC, if MARC21, it will change the leader (optional) [defaults to system preference]
283 <C$toencoding the encoding you want the record to end up in (optional) [UTF-8]
285 <C$fromencoding the encoding the record is currently in (optional, it will probably be able to tell unless there's a problem with the record)
287 FIXME: the fromencoding doesn't work yet
288 FIXME: better handling for UNIMARC, it should allow management of 100 field
289 FIXME: shouldn't have to convert to and from xml/marc just to change encoding,
290 someone needs to re-write MARC::Record's 'encoding' method to actually
291 alter the encoding rather than just changing the leader
296 my ($record,$format,$flavour,$toencoding,$fromencoding) = @_;
298 unless($flavour) {$flavour = C4::Context->preference("marcflavour")};
299 unless($toencoding) {$toencoding = "UTF-8"};
300 if (lc($format) =~ /^MARC$/o) { # ISO2790 Record
301 my $marcxml = marc2marcxml($record,$encoding,$flavour);
302 $newrecord = marcxml2marc($marcxml,$encoding,$flavour);
303 } elsif (lc($format) =~ /^MARCXML$/o) { # MARCXML Record
304 my $marc = marcxml2marc($record,$encoding,$flavour);
305 $newrecord = marc2marcxml($record,$encoding,$flavour);
307 #FIXME: handle other record formats, and finally, handle errors
312 END { } # module clean-up code here (global destructor)
320 Joshua Ferraro <jmf@liblime.com>