use C4::AuthoritiesMarc::UNIMARC;
use C4::Charset;
use C4::Log;
+use Koha::Authority;
use vars qw($VERSION @ISA @EXPORT);
&SearchAuthorities
&BuildSummary
- &BuildUnimarcHierarchies
- &BuildUnimarcHierarchy
+ &BuildAuthHierarchies
+ &BuildAuthHierarchy
+ &GenerateHierarchy
&merge
&FindDuplicateAuthority
}
} else {
my $query;
- my $attr;
+ my $attr = '';
# the marclist may contain "mainentry". In this case, search the tag_to_report, that depends on
# the authtypecode. Then, search on $a of this tag_to_report
# also store main entry MARC tag, to extract it at end of search
my $mainentrytag;
##first set the authtype search and may be multiple authorities
- my $n=0;
- my @authtypecode;
- my @auths=split / /,$authtypecode ;
- foreach my $auth (@auths){
- $query .=" \@attr 1=authtype \@attr 5=100 ".$auth; ##No truncation on authtype
- push @authtypecode ,$auth;
- $n++;
- }
- if ($n>1){
- while ($n>1){$query= "\@or ".$query;$n--;}
+ if ($authtypecode) {
+ my $n=0;
+ my @authtypecode;
+ my @auths=split / /,$authtypecode ;
+ foreach my $auth (@auths){
+ $query .=" \@attr 1=authtype \@attr 5=100 ".$auth; ##No truncation on authtype
+ push @authtypecode ,$auth;
+ $n++;
+ }
+ if ($n>1){
+ while ($n>1){$query= "\@or ".$query;$n--;}
+ }
}
my $dosearch;
elsif ( @$tags[$i] eq "mainentry" ) {
$attr = " \@attr 1=Heading ";
}
- elsif ( @$tags[$i] eq "any" ) {
- $attr = " \@attr 1=Any ";
- }
elsif ( @$tags[$i] eq "match" ) {
$attr = " \@attr 1=Match ";
}
elsif ( @$tags[$i] eq "thesaurus" ) {
$attr = " \@attr 1=Subject-heading-thesaurus ";
}
+ else { # Assume any if no index was specified
+ $attr = " \@attr 1=Any ";
+ }
if ( @$operator[$i] eq 'is' ) {
$attr .= " \@attr 4=1 \@attr 5=100 "
; ##Phrase, No truncation,all of subfield field must match
else {
$attr .= " \@attr 5=1 \@attr 4=6 "
; ## Word list, right truncated, anywhere
+ if ($sortby eq 'Relevance') {
+ $attr .= "\@attr 2=102 ";
+ }
}
@$value[$i] =~ s/"/\\"/g; # Escape the double-quotes in the search value
$attr =$attr."\"".@$value[$i]."\"";
my $thisauthtype = GetAuthType(GetAuthTypeCode($authid));
$newline{authtype} = defined ($thisauthtype) ?
$thisauthtype->{'authtypetext'} :
- GetAuthType($authtypecode)->{'authtypetext'};
+ (GetAuthType($authtypecode) ? $_->{'authtypetext'} : '');
$newline{summary} = $summary;
$newline{even} = $counter % 2;
$newline{reported_tag} = $reported_tag;
sub GetAuthority {
my ($authid)=@_;
- my $dbh=C4::Context->dbh;
- my $sth=$dbh->prepare("select authtypecode, marcxml from auth_header where authid=?");
- $sth->execute($authid);
- my ($authtypecode, $marcxml) = $sth->fetchrow;
- my $record=eval {MARC::Record->new_from_xml(StripNonXmlChars($marcxml),'UTF-8',
- (C4::Context->preference("marcflavour") eq "UNIMARC"?"UNIMARCAUTH":C4::Context->preference("marcflavour")))};
- return undef if ($@);
- $record->encoding('UTF-8');
- if (C4::Context->preference("marcflavour") eq "MARC21") {
- my ($auth_type_tag, $auth_type_subfield) = get_auth_type_location($authtypecode);
- C4::AuthoritiesMarc::MARC21::fix_marc21_auth_type_location($record, $auth_type_tag, $auth_type_subfield);
- }
- return ($record);
+ my $authority = Koha::Authority->get_from_authid($authid);
+ return ($authority->record);
}
=head2 GetAuthType
$summary{type} = $authref->{authtypetext};
$summary{summary} = $authref->{summary};
}
- my $marc21subfields = 'abcdfghjklmnopqrstuvxyz';
+ my $marc21subfields = 'abcdfghjklmnopqrstuvxyz68';
my %marc21controlrefs = ( 'a' => 'earlier',
'b' => 'later',
'd' => 'acronym',
# see :
foreach my $field ($record->field('5..')) {
if (($field->subfield('5')) && ($field->subfield('a')) && ($field->subfield('5') eq 'g')) {
- push @seealso, { $field->as_string('abcdefgjxyz'), type => 'broader', field => $field->tag() };
+ push @seealso, {
+ heading => $field->as_string('abcdefgjxyz'),
+ type => 'broader',
+ field => $field->tag(),
+ search => $field->as_string('abcdefgjxyz'),
+ authid => $field->subfield('9')
+ };
} elsif (($field->subfield('5')) && ($field->as_string) && ($field->subfield('5') eq 'h')){
- push @seealso, { heading => $field->as_string('abcdefgjxyz'), type => 'narrower', field => $field->tag() };
+ push @seealso, {
+ heading => $field->as_string('abcdefgjxyz'),
+ type => 'narrower',
+ field => $field->tag(),
+ search => $field->as_string('abcdefgjxyz'),
+ authid => $field->subfield('9')
+ };
} elsif ($field->subfield('a')) {
- push @seealso, { heading => $field->as_string('abcdefgxyz'), type => 'seealso', field => $field->tag() };
+ push @seealso, {
+ heading => $field->as_string('abcdefgxyz'),
+ type => 'seealso',
+ field => $field->tag(),
+ search => $field->as_string('abcdefgjxyz'),
+ authid => $field->subfield('9')
+ };
}
}
# // form
}
foreach my $field ($record->field('4..')) { #See From
my $type = 'seefrom';
- $type = $marc21controlrefs{substr $field->subfield('w'), 0, 1} if ($field->subfield('w'));
+ $type = ($marc21controlrefs{substr $field->subfield('w'), 0, 1} || '') if ($field->subfield('w'));
if ($type eq 'notapplicable') {
$type = substr $field->subfield('w'), 2, 1;
$type = 'earlier' if $type && $type ne 'n';
}
if ($type eq 'subfi') {
- push @seefrom, { heading => $field->as_string($marc21subfields), type => $field->subfield('i'), field => $field->tag() };
+ push @seefrom, { heading => $field->as_string($marc21subfields), type => ($field->subfield('i') || ''), field => $field->tag() };
} else {
push @seefrom, { heading => $field->as_string($marc21subfields), type => $type, field => $field->tag() };
}
}
foreach my $field ($record->field('5..')) { #See Also
my $type = 'seealso';
- $type = $marc21controlrefs{substr $field->subfield('w'), 0, 1} if ($field->subfield('w'));
+ $type = ($marc21controlrefs{substr $field->subfield('w'), 0, 1} || '') if ($field->subfield('w'));
if ($type eq 'notapplicable') {
$type = substr $field->subfield('w'), 2, 1;
$type = 'earlier' if $type && $type ne 'n';
}
if ($type eq 'subfi') {
- push @seealso, { heading => $field->as_string($marc21subfields), type => $field->subfield('i'), field => $field->tag() };
+ push @seealso, {
+ heading => $field->as_string($marc21subfields),
+ type => $field->subfield('i'),
+ field => $field->tag(),
+ search => $field->as_string($marc21subfields) || '',
+ authid => $field->subfield('9') || ''
+ };
} else {
- push @seealso, { heading => $field->as_string($marc21subfields), type => $type, field => $field->tag() };
+ push @seealso, {
+ heading => $field->as_string($marc21subfields),
+ type => $type,
+ field => $field->tag(),
+ search => $field->as_string($marc21subfields) || '',
+ authid => $field->subfield('9') || ''
+ };
}
}
foreach my $field ($record->field('6..')) {
return \%summary;
}
-=head2 BuildUnimarcHierarchies
+=head2 GetAuthorizedHeading
- $text= &BuildUnimarcHierarchies( $authid, $force)
+ $heading = &GetAuthorizedHeading({ record => $record, authid => $authid })
+
+Takes a MARC::Record object describing an authority record or an authid, and
+returns a string representation of the first authorized heading. This routine
+should be considered a temporary shim to ease the future migration of authority
+data from C4::AuthoritiesMarc to the object-oriented Koha::*::Authority.
+
+=cut
+
+sub GetAuthorizedHeading {
+ my $args = shift;
+ my $record;
+ unless ($record = $args->{record}) {
+ return unless $args->{authid};
+ $record = GetAuthority($args->{authid});
+ }
+ if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
+# construct UNIMARC summary, that is quite different from MARC21 one
+# accepted form
+ foreach my $field ($record->field('2..')) {
+ return $field->as_string('abcdefghijlmnopqrstuvwxyz');
+ }
+ } else {
+ foreach my $field ($record->field('1..')) {
+ my $tag = $field->tag();
+ next if "152" eq $tag;
+# FIXME - 152 is not a good tag to use
+# in MARC21 -- purely local tags really ought to be
+# 9XX
+ if ($tag eq '100') {
+ return $field->as_string('abcdefghjklmnopqrstvxyz68');
+ } elsif ($tag eq '110') {
+ return $field->as_string('abcdefghklmnoprstvxyz68');
+ } elsif ($tag eq '111') {
+ return $field->as_string('acdefghklnpqstvxyz68');
+ } elsif ($tag eq '130') {
+ return $field->as_string('adfghklmnoprstvxyz68');
+ } elsif ($tag eq '148') {
+ return $field->as_string('abvxyz68');
+ } elsif ($tag eq '150') {
+ return $field->as_string('abvxyz68');
+ } elsif ($tag eq '151') {
+ return $field->as_string('avxyz68');
+ } elsif ($tag eq '155') {
+ return $field->as_string('abvxyz68');
+ } elsif ($tag eq '180') {
+ return $field->as_string('vxyz68');
+ } elsif ($tag eq '181') {
+ return $field->as_string('vxyz68');
+ } elsif ($tag eq '182') {
+ return $field->as_string('vxyz68');
+ } elsif ($tag eq '185') {
+ return $field->as_string('vxyz68');
+ } else {
+ return $field->as_string();
+ }
+ }
+ }
+ return;
+}
+
+=head2 BuildAuthHierarchies
+
+ $text= &BuildAuthHierarchies( $authid, $force)
return text containing trees for hierarchies
for them to be stored in auth_header
=cut
-sub BuildUnimarcHierarchies{
- my $authid = shift @_;
+sub BuildAuthHierarchies{
+ my $authid = shift @_;
# warn "authid : $authid";
- my $force = shift @_;
- my @globalresult;
- my $dbh=C4::Context->dbh;
- my $hierarchies;
- my $data = GetHeaderAuthority($authid);
- if ($data->{'authtrees'} and not $force){
- return $data->{'authtrees'};
+ my $force = shift @_ || (C4::Context->preference('marcflavour') eq 'UNIMARC' ? 0 : 1);
+ my @globalresult;
+ my $dbh=C4::Context->dbh;
+ my $hierarchies;
+ my $data = GetHeaderAuthority($authid);
+ if ($data->{'authtrees'} and not $force){
+ return $data->{'authtrees'};
# } elsif ($data->{'authtrees'}){
# $hierarchies=$data->{'authtrees'};
- } else {
- my $record = GetAuthority($authid);
- my $found;
- return unless $record;
- foreach my $field ($record->field('5..')){
- if ($field->subfield('5') && $field->subfield('5') eq 'g'){
- my $subfauthid=_get_authid_subfield($field);
- next if ($subfauthid eq $authid);
- my $parentrecord = GetAuthority($subfauthid);
- my $localresult=$hierarchies;
- my $trees;
- $trees = BuildUnimarcHierarchies($subfauthid);
- my @trees;
- if ($trees=~/;/){
- @trees = split(/;/,$trees);
- } else {
- push @trees, $trees;
- }
- foreach (@trees){
- $_.= ",$authid";
+ } else {
+ my $record = GetAuthority($authid);
+ my $found;
+ return unless $record;
+ foreach my $field ($record->field('5..')){
+ my $broader = 0;
+ $broader = 1 if (
+ (C4::Context->preference('marcflavour') eq 'UNIMARC' && $field->subfield('5') && $field->subfield('5') eq 'g') ||
+ (C4::Context->preference('marcflavour') ne 'UNIMARC' && $field->subfield('w') && substr($field->subfield('w'), 0, 1) eq 'g'));
+ if ($broader) {
+ my $subfauthid=_get_authid_subfield($field) || '';
+ next if ($subfauthid eq $authid);
+ my $parentrecord = GetAuthority($subfauthid);
+ next unless $parentrecord;
+ my $localresult=$hierarchies;
+ my $trees;
+ $trees = BuildAuthHierarchies($subfauthid);
+ my @trees;
+ if ($trees=~/;/){
+ @trees = split(/;/,$trees);
+ } else {
+ push @trees, $trees;
+ }
+ foreach (@trees){
+ $_.= ",$authid";
+ }
+ @globalresult = (@globalresult,@trees);
+ $found=1;
+ }
+ $hierarchies=join(";",@globalresult);
}
- @globalresult = (@globalresult,@trees);
- $found=1;
- }
- $hierarchies=join(";",@globalresult);
+#Unless there is no ancestor, I am alone.
+ $hierarchies="$authid" unless ($hierarchies);
}
- #Unless there is no ancestor, I am alone.
- $hierarchies="$authid" unless ($hierarchies);
- }
- AddAuthorityTrees($authid,$hierarchies);
- return $hierarchies;
+ AddAuthorityTrees($authid,$hierarchies);
+ return $hierarchies;
}
-=head2 BuildUnimarcHierarchy
+=head2 BuildAuthHierarchy
- $ref= &BuildUnimarcHierarchy( $record, $class,$authid)
+ $ref= &BuildAuthHierarchy( $record, $class,$authid)
return a hashref in order to display hierarchy for record and final Authid $authid
"current_value"
"value"
-"ifparents"
-"ifchildren"
-Those two latest ones should disappear soon.
+=cut
+
+sub BuildAuthHierarchy{
+ my $record = shift @_;
+ my $class = shift @_;
+ my $authid_constructed = shift @_;
+ return unless ($record && $record->field('001'));
+ my $authid=$record->field('001')->data();
+ my %cell;
+ my $parents=""; my $children="";
+ my (@loopparents,@loopchildren);
+ my $marcflavour = C4::Context->preference('marcflavour');
+ my $relationshipsf = $marcflavour eq 'UNIMARC' ? '5' : 'w';
+ foreach my $field ($record->field('5..')){
+ my $subfauthid=_get_authid_subfield($field);
+ if ($subfauthid && $field->subfield($relationshipsf) && $field->subfield('a')){
+ my $relationship = substr($field->subfield($relationshipsf), 0, 1);
+ if ($relationship eq 'h'){
+ push @loopchildren, { "authid"=>$subfauthid,"value"=>$field->subfield('a')};
+ }
+ elsif ($relationship eq 'g'){
+ push @loopparents, { "authid"=>$subfauthid,"value"=>$field->subfield('a')};
+ }
+# brothers could get in there with an else
+ }
+ }
+ $cell{"parents"}=\@loopparents;
+ $cell{"children"}=\@loopchildren;
+ $cell{"class"}=$class;
+ $cell{"authid"}=$authid;
+ $cell{"current_value"} =1 if ($authid eq $authid_constructed);
+ $cell{"value"}=C4::Context->preference('marcflavour') eq 'UNIMARC' ? $record->subfield('2..',"a") : $record->subfield('1..', 'a');
+ return \%cell;
+}
+
+=head2 BuildAuthHierarchyBranch
+
+ $branch = &BuildAuthHierarchyBranch( $tree, $authid[, $cnt])
+
+Return a data structure representing an authority hierarchy
+given a list of authorities representing a single branch in
+an authority hierarchy tree. $authid is the current node in
+the tree (which may or may not be somewhere in the middle).
+$cnt represents the level of the upper-most item, and is only
+used when BuildAuthHierarchyBranch is called recursively (i.e.,
+don't ever pass in anything but zero to it).
=cut
-sub BuildUnimarcHierarchy{
- my $record = shift @_;
- my $class = shift @_;
- my $authid_constructed = shift @_;
- return undef unless ($record);
- my $authid=$record->field('001')->data();
- my %cell;
- my $parents=""; my $children="";
- my (@loopparents,@loopchildren);
- foreach my $field ($record->field('5..')){
- my $subfauthid=_get_authid_subfield($field);
- if ($subfauthid && $field->subfield('5') && $field->subfield('a')){
- if ($field->subfield('5') eq 'h'){
- push @loopchildren, { "childauthid"=>$field->subfield('3'),"childvalue"=>$field->subfield('a')};
- }
- elsif ($field->subfield('5') eq 'g'){
- push @loopparents, { "parentauthid"=>$field->subfield('3'),"parentvalue"=>$field->subfield('a')};
- }
- # brothers could get in there with an else
- }
- }
- $cell{"ifparents"}=1 if (scalar(@loopparents)>0);
- $cell{"ifchildren"}=1 if (scalar(@loopchildren)>0);
- $cell{"loopparents"}=\@loopparents if (scalar(@loopparents)>0);
- $cell{"loopchildren"}=\@loopchildren if (scalar(@loopchildren)>0);
- $cell{"class"}=$class;
- $cell{"loopauthid"}=$authid;
- $cell{"current_value"} =1 if $authid eq $authid_constructed;
- $cell{"value"}=$record->subfield('2..',"a");
- return \%cell;
+sub BuildAuthHierarchyBranch {
+ my ($tree, $authid, $cnt) = @_;
+ $cnt |= 0;
+ my $elementdata = GetAuthority(shift @$tree);
+ my $branch = BuildAuthHierarchy($elementdata,"child".$cnt, $authid);
+ if (scalar @$tree > 0) {
+ my $nextBranch = BuildAuthHierarchyBranch($tree, $authid, ++$cnt);
+ my $nextAuthid = $nextBranch->{authid};
+ my $found;
+ # If we already have the next branch listed as a child, let's
+ # replace the old listing with the new one. If not, we will add
+ # the branch at the end.
+ foreach my $cell (@{$branch->{children}}) {
+ if ($cell->{authid} eq $nextAuthid) {
+ $cell = $nextBranch;
+ $found = 1;
+ last;
+ }
+ }
+ push @{$branch->{children}}, $nextBranch unless $found;
+ }
+ return $branch;
+}
+
+=head2 GenerateHierarchy
+
+ $hierarchy = &GenerateHierarchy($authid);
+
+Return an arrayref holding one or more "trees" representing
+authority hierarchies.
+
+=cut
+
+sub GenerateHierarchy {
+ my ($authid) = @_;
+ my $trees = BuildAuthHierarchies($authid);
+ my @trees = split /;/,$trees ;
+ push @trees,$trees unless (@trees);
+ my @loophierarchies;
+ foreach my $tree (@trees){
+ my @tree=split /,/,$tree;
+ push @tree, $tree unless (@tree);
+ my $branch = BuildAuthHierarchyBranch(\@tree, $authid);
+ push @loophierarchies, [ $branch ];
+ }
+ return \@loophierarchies;
}
sub _get_authid_subfield{
} else {
#zebra connection
my $oConnection=C4::Context->Zconn("biblioserver",0);
- my $oldSyntax = $oConnection->option("preferredRecordSyntax");
- $oConnection->option("preferredRecordSyntax"=>"XML");
+ # We used to use XML syntax here, but that no longer works.
+ # Thankfully, we don't need it.
my $query;
$query= "an=".$mergefrom;
my $oResult = $oConnection->search(new ZOOM::Query::CCL2RPN( $query, $oConnection ));
my $rec;
$rec=$oResult->record($z);
my $marcdata = $rec->raw();
- my $marcrecordzebra= MARC::Record->new_from_xml($marcdata,"utf8",C4::Context->preference("marcflavour"));
+ my $marcrecordzebra= MARC::Record->new_from_usmarc($marcdata);
my ( $biblionumbertagfield, $biblionumbertagsubfield ) = &GetMarcFromKohaField( "biblio.biblionumber", '' );
- my $i = $marcrecordzebra->subfield($biblionumbertagfield, $biblionumbertagsubfield);
+ my $i = ($biblionumbertagfield < 10) ? $marcrecordzebra->field($biblionumbertagfield)->data : $marcrecordzebra->subfield($biblionumbertagfield, $biblionumbertagsubfield);
my $marcrecorddb=GetMarcBiblio($i);
push @reccache, $marcrecorddb;
$z++;
}
$oResult->destroy();
- $oConnection->option("preferredRecordSyntax"=>$oldSyntax);
}
#warn scalar(@reccache)." biblios to update";
# Get All candidate Tags for the change
foreach my $tagfield (@tags_using_authtype){
# warn "tagfield : $tagfield ";
foreach my $field ($marcrecord->field($tagfield)){
+ # biblio is linked to authority with $9 subfield containing authid
my $auth_number=$field->subfield("9");
my $tag=$field->tag();
if ($auth_number==$mergefrom) {
my $field_to=MARC::Field->new(($tag_to?$tag_to:$tag),$field->indicator(1),$field->indicator(2),"9"=>$mergeto);
my $exclude='9';
- foreach my $subfield (@record_to) {
+ foreach my $subfield (grep {$_->[0] ne '9'} @record_to) {
$field_to->add_subfields($subfield->[0] =>$subfield->[1]);
$exclude.= $subfield->[0];
}