1 package OpenILS::Application::Cat::Utils;
2 use strict; use warnings;
3 use OpenILS::Utils::Fieldmapper;
6 use OpenSRF::Utils::SettingsParser;
7 use OpenILS::Utils::FlatXML;
10 my $parser = XML::LibXML->new();
11 my $xslt = XML::LibXSLT->new();
12 my $xslt_doc = $parser->parse_file( "/pines/cvs/ILS/Open-ILS/xsl/MARC21slim2MODS.xsl" );
13 my $mods_sheet = $xslt->parse_stylesheet( $xslt_doc );
19 $class = ref($class) || $class;
20 return bless( {}, $class );
24 # ---------------------------------------------------------------------------
25 # Converts an XML nodeset into a tree
26 # This method expects a blessed Fieldmapper::biblio::record_node object
28 my($class, $nodeset) = @_;
31 for my $child (@$nodeset) {
32 next unless ($child and defined($child->parent_node));
33 my $parent = $nodeset->[$child->parent_node];
35 warn "No Parent For " . $child->intra_doc_id() . "\n";
37 $parent->children([]) unless defined($parent->children);
40 #$child->intra_doc_id($x++);
41 push( @{$parent->children}, $child );
48 # ---------------------------------------------------------------------------
49 # Converts a tree into an xml nodeset
50 # This method expects a blessed Fieldmapper::biblio::record_node object
53 my($self, $node, $newnodes) = @_;
55 return $newnodes unless $node;
57 if(!$newnodes) { $newnodes = []; }
59 push( @$newnodes, $node );
61 if( $node->children() ) {
63 for my $child (@{ $node->children() }) {
65 new Fieldmapper::biblio::record_node ($child);
67 if(!defined($child->parent_node)) {
68 $child->parent_node($node->intra_doc_id);
69 $child->ischanged(1); #just to be sure
72 $self->tree2nodeset( $child, $newnodes );
76 $node->children([]); #we don't need them hanging around
80 sub update_children_parents {
81 my($self, $node) = @_;
82 if( $node->children ) {
83 for my $child( @{$node->children()} ) {
84 $child->parent_node( $node->intra_doc_id() );
92 my($self, $nodeset) = @_;
94 for my $node (@$nodeset) {
95 if(!$node->isdeleted() ) {
96 push @newnodes, $node;
104 # ---------------------------------------------------------------------------
105 # Walks a nodeset and checks for insert, update, and delete and makes
106 # appropriate db calls
107 # This method expects a blessed Fieldmapper::biblio::record_node object
110 my($self, $nodeset) = @_;
116 my $size = @$nodeset;
118 # my $doc_id = undef;
120 for my $index (0..$size) {
122 my $pos = $index + $offset;
123 my $node = $nodeset->[$index];
126 # if( !defined($doc_id) ) {
127 # $doc_id = $node->owner_doc;
130 if($node->isdeleted()) {
132 warn "Deleting Node " . $node->intra_doc_id() . "\n";
133 push @_deleted, $node;
141 $node->intra_doc_id($pos);
142 warn "Adding Node $pos\n";
143 $node->owner_doc($doc_id);
149 if( ($node->intra_doc_id()
150 and $node->intra_doc_id() != $pos) ||
151 $node->ischanged() ) {
153 warn "Updating Node " . $node->intra_doc_id() . " to $pos\n";
155 $node->intra_doc_id($pos);
156 $self->update_children_parents( $node );
157 push @_altered, $node;
167 warn "Building db session\n";
168 my $session = $self->start_db_session();
171 warn "Deleting $szz\n";
174 warn "Sending deletes to db\n";
175 my $del_req = $session->request(
176 "open-ils.storage.biblio.record_node.batch.delete", @_deleted );
177 $status = $del_req->recv();
178 if(ref($status) and $status->isa("Error")) {
179 warn " +++++++ Node Delete Failed in Cat";
180 throw $status ("Node Delete Failed in Cat") ;
182 warn "Delete Successful\n";
183 $d = $status->content();
187 warn "Updating $szz\n";
190 warn "Sending updates to db\n";
191 @_altered = sort { $a->id <=> $b->id } @_altered;
192 my $alt_req = $session->request(
193 "open-ils.storage.biblio.record_node.batch.update", @_altered );
194 $status = $alt_req->recv();
195 if(ref($status) and $status->isa("Error")) {
196 warn " +++++++ Node Update Failed in Cat";
197 throw $status ("Node Update Failed in Cat");
199 warn "Update Successful\n";
200 $al = $status->content();
204 warn "Adding $szz\n";
207 warn "Sending adds to db\n";
208 my $add_req = $session->request(
209 "open-ils.storage.biblio.record_node.batch.create", @_added );
210 $status = $add_req->recv();
211 if(ref($status) and $status->isa("Error")) {
212 warn " +++++++ Node Create Failed in Cat";
213 throw $status ("Node Create Failed in Cat");
215 $added_stuff = $status->content();
216 warn "Add successful\n";
219 warn "done updating records\n";
220 $self->commit_db_session( $session );
222 my $hash = { added => $added_stuff, deleted => $d, updated => $al };
230 # on sucess, returns the created session, on failure throws ERROR exception
231 sub start_db_session {
233 my $session = OpenSRF::AppSession->connect( "open-ils.storage" );
234 my $trans_req = $session->request( "open-ils.storage.transaction.begin" );
235 my $trans_resp = $trans_req->recv();
236 if(ref($trans_resp) and $trans_resp->isa("Error")) { throw $trans_resp; }
237 if( ! $trans_resp->content() ) {
238 throw OpenSRF::ERROR ("Unable to Begin Transaction with database" );
240 $trans_req->finish();
244 # commits and destroys the session
245 sub commit_db_session {
246 my( $self, $session ) = @_;
248 my $req = $session->request( "open-ils.storage.transaction.commit" );
249 my $resp = $req->recv();
250 if(ref($resp) and $resp->isa("Error")) { throw $resp; }
253 $session->disconnect();
258 sub mods_perl_to_mods_slim {
259 my( $self, $modsperl ) = @_;
262 warn Dumper $modsperl;
264 my $title = $modsperl->{titleInfo}->{title};
265 my $author = $modsperl->{name}->{namePart};
266 if(ref($author) eq "ARRAY") {
267 $author = $author->[0];
270 return { "title" => $title, "author" => $author };
276 # ---------------------------------------------------------------------------
277 # Utility method for turning a nodes_array ($nodelist->nodelist) into
279 # ---------------------------------------------------------------------------
280 sub _nodeset_to_perl {
281 my($self, $nodeset) = @_;
282 return undef unless ($nodeset);
284 OpenILS::Utils::FlatXML->new()->nodeset_to_xml($nodeset);
286 # Evil, but for some reason necessary
287 $xmldoc = $parser->parse_string( $xmldoc->toString() );
288 my $perl = $self->marcxml_doc_to_mods_perl($xmldoc);
293 # ---------------------------------------------------------------------------
294 # Initializes a MARC -> Unified MODS batch process
295 # ---------------------------------------------------------------------------
296 sub start_mods_batch {
297 my( $self, $master_doc ) = @_;
298 $self->{master_doc} = $self->_nodeset_to_perl( $master_doc );
301 # ---------------------------------------------------------------------------
302 # Completes a MARC -> Unified MODS batch process and returns the perl hash
303 # ---------------------------------------------------------------------------
304 sub finish_mods_batch {
306 my $perl = $self->{master_doc};
307 $self->{master_doc} = undef;
311 # ---------------------------------------------------------------------------
312 # Pushes a marcxml nodeset into the current MODS batch
313 # ---------------------------------------------------------------------------
314 sub mods_push_nodeset {
315 my( $self, $nodeset ) = @_;
316 my $xmlperl = $self->_nodeset_to_perl( $nodeset );
317 for my $subject( @{$xmlperl->{subject}} ) {
318 push @{$self->{master_doc}->{subject}}, $subject;
324 # ---------------------------------------------------------------------------
325 # Transforms a MARC21SLIM XML document into a MODS formatted perl hash
326 # ---------------------------------------------------------------------------
327 sub marcxml_doc_to_mods_perl {
328 my( $self, $marcxml_doc ) = @_;
329 my $mods = $mods_sheet->transform($marcxml_doc);
330 my $perl = OpenSRF::Utils::SettingsParser::XML2perl( $mods->documentElement );
331 return $perl->{mods} if exists($perl->{mods});
337 # ---------------------------------------------------------------------------
338 # Transforms a set of marcxml nodesets into a unified MODS perl hash. The
339 # first doc is assumed to be the 'master'
340 # ---------------------------------------------------------------------------
341 sub marcxml_nodeset_list_to_mods_perl {
342 my( $self, $nodeset_list ) = @_;
343 my $master = $self->_nodeset_to_perl( shift(@$nodeset_list) );
345 for my $nodes (@$nodeset_list) {
346 my $xmlperl = $self->_nodeset_to_perl( $nodes );
347 for my $subject( @{$xmlperl->{subject}} ) {
348 push @{$master->{subject}}, $subject;
356 # not really sure if we'll ever need this one...
357 sub marcxml_doc_to_mods_nodeset {
358 my( $self, $marcxml_doc ) = @_;
359 my $mods = $mods_sheet->transform($marcxml_doc);
360 my $u = OpenILS::Utils::FlatXML->new();
361 my $nodeset = $u->xmldoc_to_nodeset( $mods );
362 return $nodeset->nodeset if $nodeset;