File Coverage

DataLoader.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package DBIx::XML::DataLoader;
2             my $VERSION="1.0b";
3              
4              
5 1     1   912 use warnings;
  1         1  
  1         28  
6 1     1   5 use strict;
  1         1  
  1         24  
7              
8 1     1   1243 use XML::XPath;
  0            
  0            
9             use LWP::UserAgent;
10             use Storable qw(dclone);
11              
12              
13             use DBIx::XML::DataLoader::MapIt;
14             use DBIx::XML::DataLoader::DB;
15             use DBIx::XML::DataLoader::IsDefined;
16              
17             ###########
18             sub new{
19             ########
20              
21             my $class=shift;
22             my $self={};
23             my %args=@_;
24             my $map=$args{map};
25             #if(!$map){die "a map file is required for creating a new object\n";}
26              
27             $self->{dbmode}=$args{dbmode}||"insertupdate";
28             $self->{dbprint}=$args{dbprint}||undef;
29             my $dbprint=$args{dbprint}||$self->{dbprint}||undef;
30             my $dbmode=$args{dbmode}||$self->{dbmode}||"insertupdate";
31              
32             $self->{map}=$args{map}||undef;
33             $self->{xml}=$args{xml}||undef;
34              
35             my @classmap=DBIx::XML::DataLoader::MapIt->mapclasses($map);
36             my @tables=@{$classmap[4]};
37             my $dbinfo=$classmap[1];
38             my $db_connections;
39             my $db=DBIx::XML::DataLoader::DB->new(dbmode=>$dbmode, dbprint=>$dbprint);
40             $self->{db}=$db;
41             if($dbinfo){
42             for my $keys (keys %{$dbinfo}){
43             my $dbuser=$dbinfo->{$keys}->{dbuser};
44             my $dbpass=$dbinfo->{$keys}->{dbpass};
45             my $dbsource=$dbinfo->{$keys}->{dbsource};
46             my $dbh;
47             $dbh=$db->DBConnect($dbuser,$dbpass,$dbsource);
48             $db_connections->{$keys}=$dbh;
49             }
50             }
51             $self->{db_connections}=$db_connections;
52             $self->{classmap}=\@classmap;
53             $self->{tables}=\@tables;
54             bless ($self, $class);
55              
56             ###############
57             } # end sub new
58             #######################
59              
60             #############################
61             sub processxml{
62             ################
63             if(scalar @_ < 3){die "failed to provide the proper arguments of xml, and map file @_\n";}
64              
65              
66             ##################
67             no strict 'refs';
68              
69             my $self=shift;
70             my %args=@_;
71             $XML::XPath::Namespaces=0;
72             my $dbprint=$args{dbprint}||$self->{dbprint}||undef;
73             my $dbmode=$args{dbmode}||$self->{dbmode}||"insertupdate";
74             my $file_count=$args{count};
75             my @classmap = @{$self->{classmap}};
76             my $xml=$args{xml};
77             if($xml){$self->{xml}=$xml;}
78             #my $map=$args{map}||$self->{map};
79             my @allxmlfiles;
80             my @allxmldocs_processed;
81             my @everybitofdata;
82             my @errors;
83              
84             my $suberrors;
85             my $dbmessage;
86             my $message;
87             my @sqlload;
88             my $dberror;
89              
90             ##################################################################
91             ### here we process our map file and get the db and xml document
92             ### structure information we need to continue
93             ###
94             my $tables=$classmap[4];
95             my $table_ref=$classmap[3];
96             my $rootelement=$classmap[2];
97             my $dbinfo=$classmap[1];
98             ####### here we make all the needed database connections
99             my $db_connections=$self->{db_connections};
100             my $db=$self->{db};
101             my $thesubs=$classmap[0];
102             my @tables=@{$tables};
103             #######################################################
104             ## here we run the pre parse subroutines
105             {no warnings; #warnings are turned off so that we will not get complaints
106             # if runsubs returns no value;
107             my ($serror, undef)=_runsubs($db_connections,$thesubs, 'prexml');
108             $suberrors.=$serror;
109             }
110             ##################################################
111              
112             #$XML::XPath::SafeMod;
113             ### we now start looping through our xml files
114             ###we do subroutine and db inserts one xml file at a time
115             my $all_xml;
116              
117             my $current_xml;
118              
119             my @arrayofallinserts;
120              
121              
122             #############################################################################
123             ## here we will check to make sure the files and directories requested
124             ## exists
125             if(!$xml){warn "we had no xml sent in";return;}
126             if($xml =~ /^http:/){
127              
128             my $ua = new LWP::UserAgent;
129             $ua->agent("DBIx_XML_DataLoader/1.0b " . $ua->agent);
130             my $req = new HTTP::Request(GET=>$xml);
131             my $res = $ua->request($req);
132             if ($res->is_success){
133             $xml=$res->content;
134             }
135             }
136              
137             if($xml =~ /^http:/){die "we did not get the remote xml map file you requested";}
138              
139              
140              
141             if($xml !~ /\
142             my $xmltype=(stat($xml))[2];
143             if($xmltype=~ /^1/){die "ERROR: The file is a directory not a regular file";}
144             if(!$xmltype){die "ERROR: The file you entered does not exist";}
145             return unless (eval{$all_xml = XML::XPath->new(filename => $xml);});
146             }
147              
148             if($xml =~ /\
149             return unless (eval{$all_xml = XML::XPath->new(xml => $xml);});
150             }
151             ##########################################################################################
152             ## below we loop through each table
153             ## and loop through the input xml file looking for items that belong in this table
154             ## once we fill all the required columns in the table we execute our SQL and empty
155             ## our colection of values and try to fill the required fields again we continue
156             ## through the document until we have no more value we can use. Then we start a new table.
157             ###########################################################################################
158             my $loopcount;
159              
160             TABLE: for my $table (@tables){
161              
162             $message.= "working with table $table\n";
163             my @table_info=@{$table_ref->{$table}};
164             my $table_details=pop @table_info;
165             my @cols=@{$table_details->{columns}};
166             my @hashof_thekeys=@{$table_details->{keys}};
167             my @thekeys;
168             for my $hash_thekey (@hashof_thekeys){
169             for my $key (keys %{$hash_thekey}){push @thekeys, $hash_thekey->{$key};}
170             }
171             my $keyelement=$table_details->{xpath};
172             my $dbname=$table_details->{dbname};
173             my $handlers=$table_details->{handlers};
174             my @tabprep;
175             my %table;
176             my $table_ref;
177             my @incols;
178             &_runtablesubs($db_connections,$handlers, 'TABLE', 'prexml');
179              
180             my $count=scalar @cols;
181             my @insdbh;
182             my @upddbh;
183             my @upkeys;
184             my $date;
185             ### we are going to try to do this looping through the map file calssmap array
186             ### looking for values that match up in the $all_xmlmap hash referance.
187             ###
188             my @currentkeys=@thekeys;
189             my $current_class;
190             my $current;
191             my @allglobals;
192             my @allresults;
193             my %array_count;
194             my $section_count;
195             my $subsection_count;
196             my $element_count;
197             my $nodecounter;
198             my $newloop="yes";
199             if(!$rootelement){$rootelement="/*";}
200             my @allnodes;
201             return unless (eval{ @allnodes = $all_xml->findnodes("$rootelement");});
202             BASENODE: while (@allnodes){
203             my $thenode=pop @allnodes;
204             my @all_tab_nodes;
205             next unless (eval { @all_tab_nodes= $thenode->findnodes("$keyelement");});
206             NODES: while (@all_tab_nodes){
207             my $node =shift @all_tab_nodes;
208              
209             CLASSLOOP: for my $class (@table_info){
210              
211             my $xpath=$class->{xpath};
212             my $default = $class->{default};
213             my $item=$default;
214             my $itemvalue=$node->findvalue($xpath);
215              
216             $itemvalue=~s/\s+/ /g;
217             ## added for testing comment out when in production
218             #if($class->{col} eq "computer_name"){$itemvalue="Comp $file_count";}
219             ## new routine in module IsDefined.pm will check to make sure a avriable has a value
220             if(defined DBIx::XML::DataLoader::IsDefined->verify($itemvalue)){$item = $itemvalue;}
221              
222             if($handlers->{$class->{col}}){
223             HANDLERS:
224             for my $key (sort keys %{$handlers->{$class->{col}}}){
225             my $sub;
226             my $handler=$handlers->{$class->{col}}->{$key}->{handler};
227             if($handler !~ /^sub/){
228             $handler=~s/>/>/;
229             my ($package, $subroutine)=split /\-\>/, $handler;
230             my $mod_name=$package.".pm";
231             &_printsuberror($mod_name, $@) unless eval {require $mod_name};
232             my @substuff;
233             push @substuff, $item,$handlers->{$class->{col}}->{$key}->{args},$db_connections->{$handlers->{$class->{col}}->{$key}->{dbname}};
234             &_printsuberror("$package->$subroutine", $@) unless (eval{$item=$package->$subroutine($item,$handlers->{$class->{col}}->{$key}->{args},$db_connections->{$handlers->{$class->{col}}->{$key}->{dbname}})});
235             }
236             if($handler=~ /^sub\{/){
237             $handler=~s/\&/\&/g;
238             $handler=~s/\"/\"/g;
239             my $subroutine=$handler;
240             $sub=eval "$subroutine";
241             {
242             no warnings;
243             &_printsuberror($sub, $@) unless (eval {$item= &$sub($item,$handlers->{$class->{col}}->{$key}->{args},$db_connections->{$handlers->{$class->{col}}->{$key}->{dbname}})});
244             }
245             }
246             } # end loop HANDLERS
247             } # if handlers
248              
249             if($class->{col}=~ /^UPDATE_DTTM$|^CREATE_DTTM$/){$item="SYSDATE";}
250             my $key;
251             KEYS: for my $ckeys(@currentkeys){
252             if($ckeys eq $class->{col}){$key="yes";last KEYS;}
253             } # end loop for keys;
254              
255             if($class->{date}){
256             my $conv_item=$db->sqldate($db_connections->{$dbname}, $item, $class->{date},$table);
257             $item=$conv_item;}
258             if(not defined $item){undef @allresults; next NODES;}
259             #{undef @allresults; next NODES;} unless (defined $item);
260             #print "Col: ",$class->{col}," Val: $item\n";
261             if(!$key){push @allresults, {val=>$item, col=>$class->{col}};}
262             if($key){push @allresults, {val=>$item, col=>$class->{col}, key=>$key};}
263             if((scalar @allresults) eq (scalar @cols)){
264             my ($tserror, $results)=_runtablesubs($db_connections,$handlers, 'TABLE', 'predb',\@allresults);
265             if($tserror){$suberrors.=$tserror;}
266             if($results){@allresults=@{$results};}
267              
268              
269             push @arrayofallinserts, {results=>[@allresults], table=>$table, keys=>\@hashof_thekeys,
270             cols=>\@cols, dbname=>$dbname};
271             undef @allresults;
272             next NODES;
273             } # end if (scalar @allresults eq scalar @thecols) and (scalar @currentkeys) <= 0)
274              
275             } # end loop CLASSLOOP
276             } # end NODES
277             } # end BASENODE
278             } # end TABLE loop
279              
280              
281             #############################################################################################
282             ## we have all of our data organized now we will prepare to run
283             ## any subs that have been passed to us from the map file and
284             ## do the database insertion or update
285             ############################################################################################
286             # we will do this so tah our subs have access to the db
287             ############################################################################
288             ## here we will walk through our extra subroutines listed in the map file###
289             ############################################################################
290             {no warnings; #warnings are turned off so that we will not get complaints
291             # if runsubs returns no value;
292             my ($serror, $allinserts)=_runsubs($db_connections,$thesubs, 'predb', \@arrayofallinserts);
293             if($allinserts =~ /^ARRAY/){
294             @arrayofallinserts=@{$allinserts};
295             }
296             $suberrors.=$serror;
297              
298             }
299             #####################################################################
300             ## we now run the actual database insertion/update subroutine dosql##
301             #####################################################################
302             if($dbinfo){
303             my ($response, $error,$load)=$db->DBInsertUpdate(datainfo=>\@arrayofallinserts, dbprint=>$dbprint,
304             dbconnections=>$db_connections, dbmode=>$dbmode);
305             if($response){$dbmessage.=$response;}
306             if($error){ $dberror.=$error;}
307             if($load){push @sqlload, $load;}
308             }
309              
310              
311             ############################ All Done ##############################
312             #&runsubs("postdb",\@subs, \@arrayofallinserts);
313              
314             #my $olddbh=pop @arrayofallinserts;
315             push @everybitofdata, \@arrayofallinserts;
316              
317              
318             $all_xml->cleanup();
319              
320              
321             {no warnings; #warnings are turned off so that we will not get complaints
322             # if runsubs returns no value;
323             my ($serror, $allinserts)=_runsubs($db_connections,$thesubs, 'postdb', \@everybitofdata);
324             $suberrors.=$serror;
325             }
326             #"We Attempted to Process the XML Document ".(join "\n", @allxmlfiles).
327             $message .=
328             "\nThe Following XML Document had data suitable for insertion into our database\n".
329             (join "\n", @allxmldocs_processed).
330             "\n____________________________________________________________\n";
331             #my %stuff=(message=>$message, dbmessage=>$dbmessage, suberrors=>$suberrors,dberrors=>$dberror, sqlload=>[@sqlload]);
332             return ($self,{message=>$message, dbmessage=>$dbmessage,suberrors=>$suberrors,dberrors=>$dberror,sqlload=>[@sqlload]});
333             } # end sub processxml;
334              
335              
336              
337              
338              
339              
340             sub _printsuberror{
341             no warnings; # here incase we do not pass all the vars we are expecting
342             my $package=shift;
343             my $error=shift;
344             my $theerrors= "We had a problem running $package, the error reported was $error\n";
345             return($theerrors);
346             }
347              
348              
349             sub _runsubs{
350              
351             no warnings; # used to keep any subs from causing warnings.
352             # errors actually generated by the subroutine that runsub will be calling
353             # are returned by runsubs
354             my $thesuberrors;
355             #my $self=shift;
356             my $db_connections=shift;
357             my $insubs=shift;
358             my $when=shift;
359             my $data=shift;
360             my $sub_response=$data;
361             if(!$insubs){return;} # chnaged here;
362             my %subs=%{$insubs->{$when}};
363             for my $key (sort keys %subs){
364             $data=$sub_response;
365             my $handler=$subs{$key}->{name};
366             my $args=$subs{$key}->{args};
367             my $dbname=$subs{$key}->{dbname};
368             my $dbconnect;
369             if($dbname){$dbconnect=$db_connections->{$dbname};}
370              
371             if($handler !~ /^sub/){
372             $handler=~s/>/>/;
373             my ($package, $subroutine)=split /\-\>/, $handler;
374             my $mod_name=$package.".pm";
375            
376             $thesuberrors.=_printsuberror($mod_name, $@)
377             unless eval {require $mod_name};
378             $thesuberrors.=_printsuberror("$package->$subroutine",$@) unless
379             (eval {$sub_response=$package->$subroutine($args, $data,
380             $dbconnect);});
381             }
382              
383             if($handler=~ /^sub\{/){
384             $handler=~s/\&/\&/g;
385             $handler=~s/\"/\"/g;
386             my $subroutine=$handler;
387             my $sub=eval "$subroutine";
388             $thesuberrors.=_printsuberror($sub, $@)
389             unless (eval {$sub_response= &$sub($args, $data, $dbconnect);});
390             }
391              
392             }
393            
394              
395             return($thesuberrors, $sub_response);
396              
397             }
398              
399              
400              
401             sub _runtablesubs{
402             no warnings; # used to keep any subs from causing warnings.
403             # errors actually generated by the subroutine that runtablesub will be calling
404             # are returned by runsubs
405              
406             #my $self=shift;
407             my $db_connections=shift;
408             my $handlers=shift;
409             my $place=shift;
410             my $when=shift;
411             my $indata=shift;
412             my $data=$indata;
413             my $subresponse=$data;
414             my $suberrors;
415             if($handlers->{$place}){
416             HANDLERS:
417             for my $key (sort keys %{$handlers->{$place}->{$when}}){
418             if($subresponse){$data=$subresponse;}
419              
420             my $sub;
421             my $handler=$handlers->{$place}->{$when}->{$key}->{handler};
422             if($handler !~ /^sub/){
423             $handler=~s/>/>/;
424             my ($package, $subroutine)=split /\-\>/, $handler;
425             my $mod_name=$package.".pm";
426             $suberrors.=_printsuberror($mod_name, $@) unless eval {require $mod_name};
427             $suberrors.=_printsuberror("$package->$subroutine", $@) unless (eval
428             {$subresponse=$package->$subroutine($handlers->{$place}->{$when}->{$key}->{args},$db_connections->{$handlers->{$place}->{$when}->{$key}->{dbname}},$data)});
429             }
430             if($handler=~ /^sub\{/){
431             $handler=~s/\&/\&/g;
432             $handler=~s/\"/\"/g;
433             my $subroutine=$handler;
434             $sub=eval "$subroutine";
435             $suberrors.=_printsuberror($sub, $@) unless
436             (eval
437             {$subresponse=&$sub($handlers->{$place}->{$when}->{$key}->{args},$db_connections->{$handlers->{$place}->{$when}->{$key}->{dbname}},$data)});
438             if(!$subresponse){$subresponse=$data;}
439             }
440              
441              
442             } # end loop HANDLERS
443             } # if handlers
444             if(!$subresponse){$subresponse=$data;}
445              
446             return($suberrors,$subresponse);
447             #################
448             } # end sub _runtablesubs
449             #######################
450              
451             1;
452              
453             __END__