utility to convert Rob's patron xml to text
[migration-tools.git] / unicorn_patron_xml2text.pl
1 #!/usr/bin/perl
2 #
3 # WARNING: This doesn't handle Rob's address-database-enhanced Patron XML format, with such things as Change of Address information
4 #
5 use strict;
6 use warnings;
7
8 use DateTime;
9 use Time::HiRes qw/time/;
10 use XML::LibXML;
11
12 my %s_map;
13
14 my $doc = XML::LibXML->new->parse_file($ARGV[0]);
15
16 my $starttime = time;
17 my $count = 1;
18
19 my @base_elements = (
20     "user_id",
21     "user_altid",
22     "user_pin",
23     "user_profile",
24     "user_status",
25     "user_priv_granted",
26     "user_priv_expires",
27     "user_mailingaddr",
28     "birthdate",
29     "last_name",
30     "first_name",
31     "middle_name",
32     "suffix_name",
33     "note",
34     "comment"
35 );
36
37 my @addr_elements = (
38     "std_line1",
39     "std_line2",
40     "std_city",
41     "std_state",
42     "std_zip",
43     "dayphone",
44     "homephone",
45     "workphone",
46     "email"
47 );
48
49 print STDOUT join("\t", @base_elements);
50 foreach my $addr ( 1..3 ) {
51     print STDOUT "\t" . join("\t", @addr_elements);
52 }
53 print STDOUT "\n";
54
55 for my $patron ( $doc->documentElement->childNodes ) {
56         next if ($patron->nodeType == 3);
57
58         my $bc = $patron->findvalue( 'user_id' );
59         if (exists($s_map{$bc})) {
60                 $count++;
61                 warn "\n!!! already saw barcode $bc, skipping\n";
62                 next;
63         } else {
64                 $s_map{$bc} = 1;
65         }
66
67         unless (defined($bc)) {
68                 my $xml = $patron->toString;
69                 warn "\n!!! no barcode found in UMS data, user number $count, xml => $xml \n";
70                 $count++;
71                 next;
72         }
73
74     foreach my $e ( @base_elements ) {
75         my $v = $patron->findvalue( $e );
76         if ( $v && ( $e eq 'birthdate' || $e eq 'user_priv_granted' || $e eq 'user_priv_expires' ) ) { $v = parse_date($v); }
77         print STDOUT ( $v ? $v : '' ) . "\t";
78     }
79
80         my %addresses;
81
82         for my $addr ( $patron->findnodes( "Address" ) ) {
83                 my $addr_type = $addr->getAttribute('addr_type');
84                 $addresses{$addr_type} = $addr;
85         }
86
87     foreach my $t ( 1..3 ) {
88         if ($addresses{$t}) {
89             foreach my $e ( @addr_elements ) {
90                 my $v = $addresses{$t}->findvalue( $e );
91                 print STDOUT ( $v ? $v : '' ) . "\t";
92             }
93         } else {
94             foreach ( @addr_elements ) { print STDOUT "\t"; }
95         }
96     }
97
98     print STDOUT "\n";
99         $count++;
100 }
101
102 sub parse_date {
103         my $string = shift;
104         my $group = shift;
105
106         my ($y,$m,$d);
107
108         if ($string eq 'NEVER') {
109                 my (undef,undef,undef,$d,$m,$y) = localtime();
110                 return sprintf('%04d-%02d-%02d', $y + 1920, $m + 1, $d);
111         } elsif (length($string) == 8 && $string =~ /^(\d{4})(\d{2})(\d{2})$/o) {
112                 ($y,$m,$d) = ($1,$2,$3);
113         } elsif ($string =~ /(\d+)\D(\d+)\D(\d+)/o) { #looks like it's parsable
114                 if ( length($3) > 2 )  { # looks like mm.dd.yyyy
115                         if ( $1 < 99 && $2 < 99 && $1 > 0 && $2 > 0 && $3 > 0) {
116                                 if ($1 > 12 && $1 < 31 && $2 < 13) { # well, actually it looks like dd.mm.yyyy
117                                         ($y,$m,$d) = ($3,$2,$1);
118                                 } elsif ($2 > 12 && $2 < 31 && $1 < 13) {
119                                         ($y,$m,$d) = ($3,$1,$2);
120                                 }
121                         }
122                 } elsif ( length($1) > 3 ) { # format probably yyyy.mm.dd
123                         if ( $3 < 99 && $2 < 99 && $1 > 0 && $2 > 0 && $3 > 0) {
124                                 if ($2 > 12 && $2 < 32 && $3 < 13) { # well, actually it looks like yyyy.dd.mm -- why, I don't konw
125                                         ($y,$m,$d) = ($1,$3,$2);
126                                 } elsif ($3 > 12 && $3 < 31 && $2 < 13) {
127                                         ($y,$m,$d) = ($1,$2,$3);
128                                 }
129                         }
130                 } elsif ( $1 < 99 && $2 < 99 && $3 < 99 && $1 > 0 && $2 > 0 && $3 > 0) {
131                         if ($3 < 7) { # probably 2000 or greater, mm.dd.yy
132                                 $y = $3 + 2000;
133                                 if ($1 > 12 && $1 < 32 && $2 < 13) { # well, actually it looks like dd.mm.yyyy
134                                         ($m,$d) = ($2,$1);
135                                 } elsif ($2 > 12 && $2 < 32 && $1 < 13) {
136                                         ($m,$d) = ($1,$2);
137                                 }
138                         } else { # probably before 2000, mm.dd.yy
139                                 $y = $3 + 1900;
140                                 if ($1 > 12 && $1 < 32 && $2 < 13) { # well, actually it looks like dd.mm.yyyy
141                                         ($m,$d) = ($2,$1);
142                                 } elsif ($2 > 12 && $2 < 32 && $1 < 13) {
143                                         ($m,$d) = ($1,$2);
144                                 }
145                         }
146                 }
147         }
148
149         my $date;
150         if ($y && $m && $d) {
151                 eval {
152                         $date = sprintf('%04d-%02d-%-2d',$y, $m, $d)
153                                 if (new DateTime ( year => $y, month => $m, day => $d ));
154                 }
155         }
156
157         return $date;
158 }
159