—package
MARC::Moose::Record;
# ABSTRACT: MARC::Moose bibliographic record
$MARC::Moose::Record::VERSION
=
'1.0.49'
;
use
Moose;
use
Modern::Perl;
use
Carp;
has
lint
=> (
is
=>
'rw'
,
);
has
leader
=> (
is
=>
'ro'
,
isa
=>
'Str'
,
writer
=>
'_leader'
,
default
=>
' '
x 24,
);
has
fields
=> (
is
=>
'rw'
,
isa
=>
'ArrayRef'
,
default
=>
sub
{ [] }
);
# Global
# Les formater standards
my
$formater
= {
iso2709
=> MARC::Moose::Formater::Iso2709->new(),
json
=> MARC::Moose::Formater::Json->new(),
legacy
=> MARC::Moose::Formater::Legacy->new(),
marcxml
=> MARC::Moose::Formater::Marcxml->new(),
text
=> MARC::Moose::Formater::Text->new(),
yaml
=> MARC::Moose::Formater::Yaml->new(),
unimarctomarc21
=> MARC::Moose::Formater::UnimarcToMarc21->new(),
authorityunimarctomarc21
=> MARC::Moose::Formater::AuthorityUnimarcToMarc21->new(),
};
# Les parser standards
my
$parser
= {
iso2709
=> MARC::Moose::Parser::Iso2709->new(),
marcxml
=> MARC::Moose::Parser::MarcxmlSax->new(),
legacy
=> MARC::Moose::Parser::Legacy->new(),
yaml
=> MARC::Moose::Parser::Yaml->new(),
json
=> MARC::Moose::Parser::Json->new(),
};
{
$MARC::Moose::Record::formater
=
$formater
;
$MARC::Moose::Record::parser
=
$parser
;
}
sub
clone {
my
$self
=
shift
;
my
$record
= MARC::Moose::Record->new();
$record
->_leader(
$self
->leader );
$record
->fields( [
map
{
$_
->clone(); } @{
$self
->fields} ] );
return
$record
;
}
sub
set_leader_length {
my
(
$self
,
$length
,
$offset
) =
@_
;
carp
"Record length of $length is larger than the MARC spec allows 99999"
if
$length
> 99999;
my
$leader
=
$self
->leader;
substr
(
$leader
, 0, 5) =
sprintf
(
"%05d"
,
$length
);
substr
(
$leader
, 12, 5) =
sprintf
(
"%05d"
,
$offset
);
# Default leader various pseudo variable fields
# Force UNICODE MARC21: substr($leader, 9, 1) = 'a';
substr
(
$leader
, 10, 2) =
'22'
;
substr
(
$leader
, 20, 4) =
'4500'
;
$self
->_leader(
$leader
);
}
sub
append {
my
$self
=
shift
;
my
@fields
=
@_
;
return
unless
@fields
;
# Control field correctness
for
my
$field
(
@fields
) {
unless
(
ref
(
$field
) =~ /^MARC::Moose::Field/ ) {
carp
"Append a non MARC::Moose::Field"
;
return
;
}
}
my
$tag
=
$fields
[0]->tag;
my
@sf
;
my
$notdone
= 1;
for
my
$field
( @{
$self
->fields} ) {
if
(
$notdone
&&
$field
->tag gt
$tag
) {
push
@sf
,
@fields
;
$notdone
= 0;
}
push
@sf
,
$field
;
}
push
@sf
,
@fields
if
$notdone
;
$self
->fields( \
@sf
);
}
my
%_field_regex
;
sub
field {
my
$self
=
shift
;
my
@specs
=
@_
;
my
@list
;
for
my
$tag
(
@specs
) {
my
$regex
=
$_field_regex
{
$tag
};
# Compile & stash it if necessary
unless
(
$regex
) {
$regex
=
qr/^$tag$/
;
$_field_regex
{
$tag
} =
$regex
;
}
for
my
$field
( @{
$self
->fields} ) {
if
(
$field
->tag =~
$regex
) {
return
$field
unless
wantarray
;
push
@list
,
$field
;
}
}
}
wantarray
?
@list
:
@list
?
$list
[0] :
undef
;
}
sub
delete
{
my
$self
=
shift
;
return
unless
@_
;
$self
->fields( [
grep
{
my
$tag
=
$_
->tag;
my
$keep
= 1;
for
my
$tag_spec
(
@_
) {
if
(
$tag
=~
$tag_spec
) {
$keep
= 0;
last
; }
}
$keep
;
} @{
$self
->fields} ] );
}
sub
as {
my
(
$self
,
$format
) =
@_
;
my
$f
=
$formater
->{
lc
(
$format
) };
return
$f
?
$f
->
format
(
$self
) :
undef
;
}
sub
new_from {
my
(
$record
,
$type
) =
@_
;
my
$p
=
$parser
->{
lc
(
$type
) };
$p
?
$p
->parse(
$record
) :
undef
;
}
sub
check {
my
$self
=
shift
;
$self
->lint ?
$self
->lint->check(
$self
) : ();
}
__PACKAGE__->meta->make_immutable;
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
MARC::Moose::Record - MARC::Moose bibliographic record
=head1 VERSION
version 1.0.49
=head1 DESCRIPTION
MARC::Moose::Record is an object, Moose based object, representing a MARC::Moose
bibliographic record. It can be a MARC21, UNIMARC, or whatever biblio record.
=head1 ATTRIBUTES
=head2 lint
A L<MARC::Moose::Lint::Checker> object which allow to check record based on a
set of validation rules. Generally, the 'lint' attribute of record is inherited
from the reader used to get the record.
=head2 leader
Read-only string. The leader is fixed by set_leader_length method.
=head2 fields
ArrayRef on MARC::Moose::Field objects: MARC::Moose:Fields::Control and
MARC::Moose::Field::Std.
=head1 METHODS
=head2 clone()
Clone the record. Create a new record containing exactly the same data.
=head2 set_leader_length( I<length>, I<offset> )
This method is called to reset leader length of record and offset of data
section. This means something only for ISO2709 formated records. So this method
is exlusively called by any formater which has to build a valid ISO2709 data
stream. It also forces leader position 10 and 20-23 since this variable values
aren't variable at all for any ordinary MARC record.
Called by L<MARC::Moose::Formater::Iso2709>.
$record->set_leader_length( $length, $offset );
=head2 append( I<field> )
Append a MARC::Moose::Field in the record. The record is appended at the end of
numerical section, ie if you append for example a 710 field, it will be placed
at the end of the 7xx fields section, just before 8xx section or at the end of
fields list.
$record->append(
MARC::Moose::Field::Std->new(
tag => '100',
subf => [ [ a => 'Poe, Edgar Allan' ],
[ u => 'Translation' ] ]
) );
You can also append an array of MARC::Moose::Field. In this case, the array
will be appended as for a unique field at the position of the first field of
the array.
=head2 field( I<tag> )
Returns a list of tags that match the field specifier, or an empty list if
nothing matched. In scalar context, returns the first matching tag, or undef
if nothing matched.
The field specifier can be a simple number (i.e. "245"), or use the "."
notation of wildcarding (i.e. subject tags are "6.."). All fields are returned
if "..." is specified.
=head2 delete(spec1, spec2, ...)
Delete all fields with tags matching the given specification. For example:
$record->delete('11.', '\d\d9');
will delete all fields with tag begining by '11' and ending with '9'.
=head2 as( I<format> )
Returns a formated version of the record as defined by I<format>. Format are standard
formater provided by the MARC::Moose::Record package: Iso2709, Text, Marcxml,
Json, Yaml, Legacy.
=head1 SYNOPSYS
use MARC::Moose::Record;
use MARC::Moose::Field::Control;
use MARC::Moose::Field::Std;
use MARC::Moose::Formater::Text;
my $record = MARC::Moose::Record->new(
fields => [
MARC::Moose::Field::Control->new(
tag => '001',
value => '1234' ),
MARC::Moose::Field::Std->new(
tag => '245',
subf => [ [ a => 'MARC is dying for ever:' ], [ b => 'will it ever happen?' ] ] ),
MARC::Moose::Field::Std->new(
tag => '260',
subf => [
[ a => 'Paris:' ],
[ b => 'Usefull Press,' ],
[ c => '2010.' ],
] ),
MARC::Moose::Field::Std->new(
tag => '600',
subf => [ [ a => 'Library' ], [ b => 'Standards' ] ] ),
MARC::Moose::Field::Std->new(
tag => '900',
subf => [ [ a => 'My local field 1' ] ] ),
MARC::Moose::Field::Std->new(
tag => '901',
subf => [ [ a => 'My local field 1' ] ] ),
]
);
my $formater = MARC::Moose::Formater::Text->new();
print $formater->format( $record );
# Shortcut:
print $record->as('Text');
$record->fields( [ grep { $_->tag < 900 } @{$record->fields} ] );
print "After local fields removing:\n", $formater->format($record);
=head1 SEE ALSO
=over 4
=item *
L<MARC::Moose>
=item *
L<MARC::Moose::Field>
=back
=head1 AUTHOR
Frédéric Demians <f.demians@tamil.fr>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2024 by Frédéric Demians.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut