File Coverage

blib/lib/SeeAlso/Identifier/PND.pm
Criterion Covered Total %
statement 63 63 100.0
branch 23 26 88.4
condition 4 5 80.0
subroutine 15 15 100.0
pod 9 9 100.0
total 114 118 96.6


line stmt bran cond sub pod time code
1             package SeeAlso::Identifier::PND;
2 6     6   76925 use strict;
  6         8  
  6         136  
3 6     6   18 use warnings;
  6         4  
  6         131  
4              
5             BEGIN {
6 6     6   15 use Exporter ();
  6         8  
  6         90  
7 6     6   15 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  6         56  
  6         554  
8 6     6   12 $VERSION = '0.62';
9 6         38 @ISA = qw(Exporter);
10             #Give a hoot don't pollute, do not export more than needed by default
11 6         7 @EXPORT = qw();
12 6         6 @EXPORT_OK = qw();
13 6         100 %EXPORT_TAGS = ();
14             }
15              
16 6     6   22 use base qw( SeeAlso::Identifier::GND );
  6         10  
  6         2420  
17             #use Carp;
18              
19             #################### subroutine header end ####################
20              
21              
22             =head1 NAME
23              
24             SeeAlso::Identifier::PND - SeeAlso handling of PND Numbers (Personennormdatei)
25              
26              
27             =head1 SYNOPSIS
28              
29             my $pnd = new SeeAlso::Identifier::PND "";
30              
31             print "invalid/empty" unless $pnd; # $pnd is defined but false !
32              
33             $pnd->value( '101115658X' );
34             $pnd->value( 'PND:101115658X' );
35             $pnd->value( '(DE-588)101115658X' );
36             $pnd->value( '(DE-588a)101115658X' );
37             $pnd->value( 'http://d-nb.info/gnd/101115658X' );
38             $pnd->value; # '' or PND identifier again (101115658X)
39             $pnd; # PND identifier as URI (http://d-nb.info/gnd/101115658X)
40              
41             $pnd->canonical; # http://d-nb.info/gnd/101115658X
42              
43             $pnd->pretty; # '' or PND identifier again (101115658X)
44              
45             =head1 DESCRIPTION
46              
47             This module handles identification numbers of the former Personennormdatei (PND)
48             of the German National Library (DNB). These continue to be valid identification
49             numbers of the successor Gemeinsame Normdatei (GND).
50              
51             The constructor of SeeAlso::Identifier::PND always returns an defined identifier
52             with all methods provided by L.
53             As canonical form the URN representation of PND with prefix C
54             is used (these HTTP URIs actually resolve).
55             As hashed and "pretty" form of an PND number, the number itself is used (including check digit).
56              
57             The authority files PND, GKD and SWD have been combined to the GND (Gemeinsame
58             Norm-Datei) in early 2012, the identifiers of "legacy" records however will
59             remain valid. They already are distinct and as such the parent module
60             L handles them simultaneously. As of v0.57
61             SeeAlso::Identifier::GND is lacking support for 10-digit identifiers and
62             does not implement all possible constraints (e.g. there are conflicting
63             checksum algorithms but by looking at the identifier you can not always
64             determine the authority file it belongs to and therefore there is no
65             certainity about the correct checksum).
66              
67             This module SeeAlso::Identifier::PND does not support the legacy GND numbers
68             for former entries of GKD and SWD and therefore its realm continues to be
69             restricted to authority records for persons and names (Tn and Tp) within
70             the GND.
71              
72             For compatibility reasons with SeeAlso::Identifier::GND the objects of this
73             module are implemented as blessed hashes instead of blessed scalars as
74             they would be by inheritance from SeeAlso::Identifier.
75              
76             =head1 METHODS
77              
78             =head2 parse ( $value )
79              
80             Get and/or set the value of the PND identifier. Returns an empty string or a possibly valid PND number. You can also use this method as function.
81              
82             Older numbers begin with "10" to "16" and have 8 digits plus check digit (which might be "X"),
83             More recently (since April 2011) assigned numbers have 9 digits plus check digit(0-X) and currently begin with "10".
84             Probably at some time in 2016 the first 10-"digit" number starting with "11" will be assigned.
85              
86             Any blanks are removed from the input.
87             Informal prefixes "PND", "GND/" and the likes are permitted, also MARC organization codes "(DE-588)" and "(DE-588a)",
88             and the official URI prefix C< http://d-nb.info/gnd/ >.
89              
90             Dashes are not removed any more when parsing, since for some former GKD numbers they are the only
91             distinction.
92              
93             =cut
94              
95             sub parse {
96 151     151 1 413 local($_) = shift;
97 151 50 100     480 $_ = shift if ref($_) and scalar @_;
98              
99 151 50       240 return "" unless defined $_;
100              
101 151         204 s/\s+//g; # no kind of spaces makes sense in input data
102 151         393 s=^(?:http://d-nb.info/gnd/|[GP]ND[:/-]*\s?|\(DE-588[a]?\))([0-9xX-]+)=$1=i;
103              
104 151         150 s/^0+//;
105 151         188 tr/x/X/;
106              
107 151 100       602 return "" unless /^1[01]?\d{7}[\dX]$/;
108              
109 99         202 return $_;
110             }
111              
112              
113             =head2 value ( [$value] )
114              
115             get/set using parse, not parent's method
116              
117             =cut
118              
119             sub value {
120 166     166 1 502 my($self, $value) = @_;
121 166 100       383 $self->{value} = $self->parse($value) if defined $value;
122 166         340 return $self->{value};
123             }
124              
125              
126             =head2 valid
127              
128             Performs checksum calculation for already parsed PND numbers.
129              
130             The mod-11-checksum is constructed the same way as for the "PICA PPN" (Pica Production Number
131             of the German National Library (actually the PND identifiers simply are PICA PPNs).
132              
133             =cut
134              
135             sub valid {
136 234 100 66 234 1 1964 return undef unless $_[0]->{value} and $_[0]->{value} =~ /^1[01]?\d{7}[\dX]$/;
137 210         678 my @i = reverse split(//, $_[0]->{value});
138 210 100       438 $i[0] = 10 if $i[0] =~ /X/i;
139              
140 210         194 my ($z, $w) = (0, 1);
141 210         238 foreach ( @i ) {
142 1961         1640 $z += ($_ * $w++)};
143 210         958 return ($z % 11) == 0;
144             }
145              
146              
147             =head2 hash ( [$value] )
148              
149             Sets and/or gets a form of the identifier suitable for processing.
150             In this class this will yield the same form as "parse", provided
151             it passes the "valid" test(s).
152              
153             =cut
154              
155             sub hash {
156 84     84 1 98 my $self = shift @_;
157 84 100       148 if ( defined $_[0] ) {
158 49 100       119 if ( $_[0] =~ /^1[01]?\d{7}[\dXx]$/ ) {
159 21         32 $self->value($_[0])}
160             else {
161 28         81 return $self->{value} = undef}
162             }
163 56 100       67 return $self->valid ? $self->{value} : "";
164             }
165              
166              
167             =head2 indexed ( [$value] )
168              
169             This is only since the parent class L as of v0.57
170             is not compliant to the interfaces specified by L
171             with respect to "indexed" being an alias for "hash".
172              
173             =cut
174              
175             sub indexed {
176 11     11 1 17 my $self = shift @_;
177 11         20 return $self->hash;
178             }
179              
180              
181             =head2 canonical ( [$value] )
182              
183             Yields the (for SeeAlso) canonical form of the identifier (if valid) as
184             an URI.
185              
186             =cut
187              
188             sub canonical {
189 139     139 1 263 my $self = shift @_;
190 139 100       226 if ( defined $_[0] ) {
191 51 100       126 if ( $_[0] =~ m=^http://d-nb.info/gnd/= ) {
192 43         58 $self->value($_[0])}
193             else {
194 8         28 return $self->{value} = undef}
195             }
196 131 100       162 return $self->valid ? ("http://d-nb.info/gnd/" . $self->{value}) : "";
197             }
198              
199              
200             =head2 normalized ( [$value] )
201              
202             This is only since the parent class L as of v0.57
203             is not compliant to the interfaces specified by L
204             with respect to "normalized" being an alias for "canonical".
205              
206             =cut
207              
208             sub normalized {
209 11     11 1 18 my $self = shift @_;
210 11         17 return $self->canonical;
211             }
212              
213              
214             =head2 cmp ( $value )
215              
216             For comparisons a "numerical" order is established by left-padding
217             the identifiers with sufficiently many zeroes.
218              
219             =cut
220              
221             sub cmp {
222 11     11 1 308 my $self = shift;
223 11         29 my $string1 = sprintf("%010s", $self->{value});
224 11         13 my $class = ref($self);
225 11         8 my $second = shift;
226 11         22 my $string2 = sprintf("%010s", $class->new($second)->{value});
227 11         74 return $string1 cmp $string2;
228             }
229              
230              
231             =head2 pretty
232              
233             Try to give the most official form of the identifier.
234              
235             =cut
236              
237             sub pretty {
238 13     13 1 19 my $self = shift @_;
239 13 50       22 return $self->valid ? $self->{value} : "";
240             }
241              
242              
243             =head1 AUTHOR
244              
245             Thomas Berger C<< >>
246              
247             =head1 ACKNOWLEDGEMENTS
248              
249             Jakob Voss C<< >> crafted SeeAlso::Identifier::GND.
250              
251             =head1 COPYRIGHT
252              
253             This program is free software; you can redistribute
254             it and/or modify it under the same terms as Perl itself.
255              
256             The full text of the license can be found in the
257             LICENSE file included with this module.
258              
259              
260             =head1 SEE ALSO
261              
262             perl(1), L.
263              
264             =cut
265              
266             #################### main pod documentation end ###################
267              
268              
269             1;
270             # The preceding line will help the module return a true value
271