@@ -, +, @@ --- C4/ImportExportFramework.pm | 986 ++++++++++++++++++++ admin/import_export_framework.pl | 68 ++ .../intranet-tmpl/prog/en/css/staff-global.css | 48 + .../prog/en/modules/admin/biblio_framework.tmpl | 141 +++ 4 files changed, 1243 insertions(+), 0 deletions(-) create mode 100755 C4/ImportExportFramework.pm create mode 100755 admin/import_export_framework.pl mode change 100644 => 100755 koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css mode change 100644 => 100755 koha-tmpl/intranet-tmpl/prog/en/modules/admin/biblio_framework.tmpl --- a/C4/ImportExportFramework.pm +++ a/C4/ImportExportFramework.pm @@ -0,0 +1,986 @@ +package C4::ImportExportFramework; + +# Copyright 2010-2011 MASmedios.com y Ministerio de Cultura +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; +use XML::LibXML; +use XML::LibXML::XPathContext; +use Digest::MD5 qw(md5_base64); +use POSIX qw(strftime); + +use C4::Context; +use C4::Debug; + + +use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); + +BEGIN { + $VERSION = 3.03; # set version for version checking + require Exporter; + @ISA = qw(Exporter); + @EXPORT = qw( + &ExportFramework + &ImportFramework + &createODS + ); +} + + +use constant XMLSTR => ' + + + + + + + + + + + + +'; + + +use constant ODSSTR => ' + + + + +'; + + +use constant ODS_STYLES_STR => ' + + + + + +'; + + +use constant ODS_SETTINGS_STR => ' + + +0 +0 +2000 +900 + +View1 + +01000020000 + + +Sheet1 +270 +0 +100 +50 +false +true +true +true +12632256 +true +true +true +true +false +false +true + + +true +true +true +12632256 +true +3 +true +true +true +false +false +true +true +Generic Printer +true +0 +false +false +true +false + +'; + + +use constant ODS_MANIFEST_STR => ' + + + + + + + + + + + + + + + + + +'; + + +=head1 NAME + +C4::ImportExportFramework - Import/Export Framework to Excel-xml/ODS Module Functions + +=head1 SYNOPSIS + + use C4::ImportExportFramework; + +=head1 DESCRIPTION + +Module to Import/Export Framework to Excel-xml/ODS on intranet administration - MARC Frameworks section + +Module to Import/Export Framework to Excel-xml/ODS on intranet administration - MARC Frameworks section +exporting the tables marc_tag_structure, marc_subfield_structure to excel-xml/ods or viceversa + +Functions for handling import/export. + + +=head1 SUBROUTINES + + + +=head2 ExportFramework + +Export all the information of a Framework to an excel "xml" file or OpenDocument SpreadSheet "ods" file. + +return : +succes + +=cut + +sub ExportFramework +{ + my ($frameworkcode, $xmlStrRef, $mode) = @_; + + my $dbh = C4::Context->dbh; + if ($dbh) { + my $dom; + my $root; + my $elementSS; + eval { + my $parser = XML::LibXML->new(); + $dom = $parser->parse_string(($mode && $mode eq 'ods')?ODSSTR:XMLSTR); + if ($dom) { + $root = $dom->documentElement(); + if ($mode && $mode eq 'ods') { + my $elementBody = $dom->createElement('office:body'); + $root->appendChild($elementBody); + $elementSS = $dom->createElement('office:spreadsheet'); + $elementBody->appendChild($elementSS); + } + } + }; + if ($@) { + $debug and warn "Error ExportFramework $@\n"; + return 0; + } + if (_export_table('marc_tag_structure', $dbh, $dom, ($mode && $mode eq 'ods')?$elementSS:$root, $frameworkcode, $mode)) { + if (_export_table('marc_subfield_structure', $dbh, $dom, ($mode && $mode eq 'ods')?$elementSS:$root, $frameworkcode, $mode)) { + $$xmlStrRef = $dom->toString(1); + return 1; + } + } + } + return 0; +}#ExportFramework + + + + +# Export all the data from a mysql table to an spreadsheet. +sub _export_table +{ + my ($table, $dbh, $dom, $root, $frameworkcode, $mode) = @_; + + if ($mode && $mode eq 'ods') { + _export_table_ods($table, $dbh, $dom, $root, $frameworkcode); + } else { + _export_table_excel($table, $dbh, $dom, $root, $frameworkcode); + } +} + + +# Export the mysql table to an ods file +sub _export_table_ods +{ + my ($table, $dbh, $dom, $root, $frameworkcode) = @_; + + eval { + my $elementTable = $dom->createElement('table:table'); + $elementTable->setAttribute('table:name', $table); + $elementTable->setAttribute('table:print', 'false'); + $root->appendChild($elementTable); + my $elementRow = $dom->createElement('table:table-row'); + $elementTable->appendChild($elementRow); + + my $elementCell; + my $elementData; + # First row with the name of the columns + my $query = 'SHOW COLUMNS FROM ' . $table; + my $sth = $dbh->prepare($query); + $sth->execute(); + my @fields = (); + while (my $hashRef = $sth->fetchrow_hashref) { + $elementCell = $dom->createElement('table:table-cell'); + $elementCell->setAttribute('office:value-type', 'string'); + $elementCell->setAttribute('office:value', $hashRef->{Field}); + $elementRow->appendChild($elementCell); + $elementData = $dom->createElement('text:p'); + $elementCell->appendChild($elementData); + $elementData->appendTextNode($hashRef->{Field}); + push @fields, {name => $hashRef->{Field}, type => ($hashRef->{Type} =~ /int/i)?'float':'string'}; + } + # Populate rows with the data from mysql + $query = 'SELECT * FROM ' . $table . ' WHERE frameworkcode=?'; + $sth = $dbh->prepare($query); + $sth->execute($frameworkcode); + my $data; + while (my $hashRef = $sth->fetchrow_hashref) { + $elementRow = $dom->createElement('table:table-row'); + $elementTable->appendChild($elementRow); + for (@fields) { + $data = $hashRef->{$_->{name}}; + if ($_->{type} eq 'float' && !defined($data)) { + $data = '0'; + } elsif ($_->{type} eq 'string' && (!$data && $data ne '0')) { + $data = '#'; + } + $data = _parseContent2Xml($data) if ($_->{type} eq 'string'); + $elementCell = $dom->createElement('table:table-cell'); + $elementCell->setAttribute('office:value-type', $_->{type}); + $elementCell->setAttribute('office:value', $data); + $elementRow->appendChild($elementCell); + $elementData = $dom->createElement('text:p'); + $elementCell->appendChild($elementData); + $elementData->appendTextNode($data); + } + } + }; + if ($@) { + $debug and warn "Error _export_table_ods $@\n"; + return 0; + } + return 1; +}#_export_table_ods + + +# Export the mysql table to an excel-xml (openoffice/libreoffice compatible) file +sub _export_table_excel +{ + my ($table, $dbh, $dom, $root, $frameworkcode) = @_; + + eval { + my $elementWS = $dom->createElement('Worksheet'); + $elementWS->setAttribute('ss:Name', $table); + $root->appendChild($elementWS); + my $elementTable = $dom->createElement('ss:Table'); + $elementWS->appendChild($elementTable); + my $elementRow = $dom->createElement('ss:Row'); + $elementTable->appendChild($elementRow); + + # First row with the name of the columns + my $elementCell; + my $elementData; + my $query = 'SHOW COLUMNS FROM ' . $table; + my $sth = $dbh->prepare($query); + $sth->execute(); + my @fields = (); + while (my $hashRef = $sth->fetchrow_hashref) { + $elementCell = $dom->createElement('ss:Cell'); + $elementCell->setAttribute('ss:StyleID', 's27'); + $elementRow->appendChild($elementCell); + $elementData = $dom->createElement('ss:Data'); + $elementData->setAttribute('ss:Type', 'String'); + $elementCell->appendChild($elementData); + $elementData->appendTextNode($hashRef->{Field}); + push @fields, {name => $hashRef->{Field}, type => ($hashRef->{Type} =~ /int/i)?'Number':'String'}; + } + # Populate rows with the data from mysql + $query = 'SELECT * FROM ' . $table . ' WHERE frameworkcode=?'; + $sth = $dbh->prepare($query); + $sth->execute($frameworkcode); + my $data; + while (my $hashRef = $sth->fetchrow_hashref) { + $elementRow = $dom->createElement('ss:Row'); + $elementTable->appendChild($elementRow); + for (@fields) { + $elementCell = $dom->createElement('ss:Cell'); + $elementRow->appendChild($elementCell); + $elementData = $dom->createElement('ss:Data'); + $elementData->setAttribute('ss:Type', $_->{type}); + $elementCell->appendChild($elementData); + $data = $hashRef->{$_->{name}}; + if ($_->{type} eq 'Number' && !defined($data)) { + $data = '0'; + } elsif ($_->{type} eq 'String' && (!$data && $data ne '0')) { + $data = '#'; + } + $elementData->appendTextNode(($_->{type} eq 'String')?_parseContent2Xml($data):$data); + } + } + }; + if ($@) { + $debug and warn "Error _export_table_excel $@\n"; + return 0; + } + return 1; +}#_export_table_excel + + + + + + + +# Format chars problematics to a correct format for xml. +sub _parseContent2Xml +{ + my $content = shift; + + $content =~ s/\&(?![a-zA-Z#0-9]{1,4};)/&/g; + $content =~ s//>/g; + return $content; +}#_parseContent2Xml + + +# Get the tmp directory on the system +sub _getTmp +{ + my $tmp = '/tmp'; + if ($ENV{'TMP'} && -d $ENV{'TMP'}) { + $tmp = $ENV{'TMP'}; + } elsif ($ENV{'TMPDIR'} && -d $ENV{'TMPDIR'}) { + $tmp = $ENV{'TMPDIR'}; + } elsif ($ENV{'TEMP'} && -d $ENV{'TEMP'}) { + $tmp = $ENV{'TEMP'}; + } + return $tmp; +}#_getTmp + + +# Create our tempdir directory for the ods process +sub _createTmpDir +{ + my $tmp = shift; + + my $tempdir = (-d $tmp)?$tmp . '/':'./'; + $tempdir .= 'tmp_ods_' . Digest::MD5::md5_hex(Digest::MD5::md5_hex(time().{}.rand().{}.$$)); + eval { + mkdir $tempdir; + }; + if ($@) { + return undef; + } else { + return $tempdir; + } +}#_createTmpDir + +=head2 createODS + +Creates a temporary directory to create the ods file and read it to store its content in a string. + +return : +success + +=cut + +sub createODS +{ + my ($strContent, $lang, $strODSRef) = @_; + + my $tmp = _getTmp(); + my $tempModule = 1; + my $tempdir; + eval { + require File::Temp; + import File::Temp qw/ tempfile tempdir /; + $tempdir = tempdir ( 'tmp_ods_' . $$ . '_XXXXXXXX', DIR => (-d $tmp)?$tmp:'.', CLEANUP => 1); + }; + if ($@) { + $tempModule = 0; + $tempdir = _createTmpDir($tmp); + } + if ($tempdir) { + # populate tempdir directory with the ods elements + eval { + if (open(OUT, "> $tempdir/content.xml")) { + print OUT $strContent; + close(OUT); + } + if (open(OUT, "> $tempdir/mimetype")) { + print OUT 'application/vnd.oasis.opendocument.spreadsheet'; + close(OUT); + } + if (open(OUT, "> $tempdir/meta.xml")) { + print OUT _getMeta($lang); + close(OUT); + } + if (open(OUT, "> $tempdir/styles.xml")) { + print OUT ODS_STYLES_STR; + close(OUT); + } + if (open(OUT, "> $tempdir/settings.xml")) { + print OUT ODS_SETTINGS_STR; + close(OUT); + } + mkdir($tempdir.'/META-INF/'); + mkdir($tempdir.'/Configurations2/'); + mkdir($tempdir.'/Configurations2/acceleator/'); + mkdir($tempdir.'/Configurations2/images/'); + mkdir($tempdir.'/Configurations2/popupmenu/'); + mkdir($tempdir.'/Configurations2/statusbar/'); + mkdir($tempdir.'/Configurations2/floater/'); + mkdir($tempdir.'/Configurations2/menubar/'); + mkdir($tempdir.'/Configurations2/progressbar/'); + mkdir($tempdir.'/Configurations2/toolbar/'); + if (open(OUT, "> $tempdir/META-INF/manifest.xml")) { + print OUT ODS_MANIFEST_STR; + close(OUT); + } + }; + if ($@) { + $debug and warn "Error createODS $@\n"; + } else { + # create ods file from tempdir directory + eval { + require Archive::Zip; + import Archive::Zip qw( :ERROR_CODES :CONSTANTS ); + my $zip = Archive::Zip->new(); + $zip->addTree( $tempdir, '' ); + $zip->writeToFileNamed('new.ods'); + }; + if ($@) { + system("cd $tempdir && zip -r new.ods ./"); + } + my $ok = 0; + # read ods file and return as a string + if (-f "$tempdir/new.ods") { + if (open (MYFILE, "$tempdir/new.ods")) { + binmode MYFILE; + my $buffer; + while (read (MYFILE, $buffer, 65536)) { + $$strODSRef .= $buffer; + } + close(MYFILE); + $ok = 1; + } + } + # delete tempdir directory + if (!$tempModule && $tempdir) { + eval { + require File::Path; + import File::Temp qw/ rmtree /; + rmtree($tempdir); + }; + if ($@) { + system("rm -rf $tempdir"); + } + } + return 1 if ($ok); + } + } + return 0; +}#createODS + + +# return Meta content for ods file +sub _getMeta +{ + my $lang = shift; + + my $myDate = strftime ("%Y-%m-%dT%H:%M:%S", localtime(time())); + my $meta = ' + + + ods-php + ' . $myDate . ' + ' . $myDate . ' + ' . $lang . ' + 2 + PT15S + + + + + + '; + return $meta; +}#_getMeta + + +=head2 ImportFramework + +Import all the information of a Framework from a excel-xml/ods file. + +return : +success + +=cut + +sub ImportFramework +{ + my ($filename, $frameworkcode, $deleteFilename) = @_; + + my $tempdir; + my $ok = -1; + my $dbh = C4::Context->dbh; + if (-r $filename && $dbh) { + my $extension = ''; + if ($filename =~ /\.(ods|xml)$/i) { + $extension = lc($1); + } else { + unlink ($filename) if ($deleteFilename); + return -1; + } + if ($extension eq 'ods') { + ($tempdir, $filename) = _openODS($filename, $deleteFilename); + } + if ($filename) { + eval { + my $parser = XML::LibXML->new(); + my $dom = $parser->parse_file($filename); + if ($dom) { + my $element; + my $root = $dom->documentElement(); + my $numDeleted = 0; + my $numDeletedAux = 0; + if (($numDeletedAux = _import_table($dbh, 'marc_tag_structure', $frameworkcode, $dom, ['frameworkcode', 'tagfield'], $extension)) >= 0) { + $numDeleted += $numDeletedAux if ($numDeletedAux > 0); + if (($numDeletedAux = _import_table($dbh, 'marc_subfield_structure', $frameworkcode, $dom, ['frameworkcode', 'tagfield', 'tagsubfield'], $extension)) >= 0) { + $numDeleted += $numDeletedAux if ($numDeletedAux > 0); + $ok = ($numDeleted > 0)?$numDeleted:0; + } + } + } else { + $debug and warn "Error ImportFramework couldn't create dom\n"; + } + }; + if ($@) { + $debug and warn "Error ImportFramework $@\n"; + } + } + unlink ($filename) if ($deleteFilename); + } else { + $debug and warn "Error ImportFramework no conex to database or not readeable $filename\n"; + } + if ($deleteFilename && $tempdir && -d $tempdir && -w $tempdir) { + eval { + require File::Path; + import File::Temp qw/ rmtree /; + rmtree($tempdir); + }; + if ($@) { + system("rm -rf $tempdir"); + } + } + return $ok; +}#ImportFramework + + +# Open (uncompress) ods file and return the content.xml file +sub _openODS +{ + my ($filename, $deleteFilename) = @_; + + my $tmp = _getTmp(); + my $tempModule = 1; + my $tempdir; + eval { + require File::Temp; + import File::Temp qw/ tempfile tempdir /; + $tempdir = tempdir ( 'tmp_ods_' . $$ . '_XXXXXXXX', DIR => (-d $tmp)?$tmp:'.', CLEANUP => 0); + }; + if ($@) { + $tempModule = 0; + $tempdir = _createTmpDir($tmp); + } + if ($tempdir) { + eval { + require Archive::Zip; + import Archive::Zip qw( :ERROR_CODES :CONSTANTS ); + my $zip = Archive::Zip->new(); + $zip->extractTree( $filename, $tempdir ); + }; + if ($@) { + system("unzip $filename -d $tempdir"); + } + if (-f "$tempdir/content.xml") { + unlink ($filename) if ($deleteFilename); + return ($tempdir, "$tempdir/content.xml"); + } + } + unlink ($filename) if ($deleteFilename); + return ($tempdir, undef); +}#_openODS + + + +# Check the table and columns corresponds with worksheet +sub _check_validity_worksheet +{ + my ($dbh, $table, $nodeFields, $fieldsA, $format) = @_; + + my $ret = 0; + eval { + my $query = 'DESCRIBE ' . $table; + my $sth = $dbh->prepare($query); + $sth->execute(); + $sth->finish; + $query = 'SHOW COLUMNS FROM ' . $table; + $sth = $dbh->prepare($query); + $sth->execute(); + my $fields = {}; + while (my $hashRef = $sth->fetchrow_hashref) { + $fields->{$hashRef->{Field}} = $hashRef->{Field}; + } + my @fields; + my $fieldsR; + if ($fieldsA) { + $fieldsR = $fieldsA; + } else { + $fieldsR = \@fields; + _getFields($nodeFields, $fieldsR, $format); + } + $ret = 1; + for (@$fieldsR) { + unless (exists($fields->{$_})) { + $ret = 0; + last; + } + } + }; + return $ret; +}#_check_validity_worksheet + + +# Import the data from an excel-xml/ods to mysql tables. +sub _import_table +{ + my ($dbh, $table, $frameworkcode, $dom, $PKArray, $format) = @_; + my %fields2Delete; + my $query; + eval { + my @fields = @$PKArray; + shift @fields; + $query = 'SELECT ' . join(',', @fields) . ' FROM ' . $table . ' WHERE frameworkcode=?'; + my $sth = $dbh->prepare($query); + $sth->execute($frameworkcode); + my $field; + while (my $hashRef = $sth->fetchrow_hashref) { + $field = ''; + map { $field .= $hashRef->{$_} . '_'; } @fields; + chop $field; + $fields2Delete{$field} = 1; + } + $sth->finish; + }; + my $ok = 0; + if ($format && $format eq 'ods') { + $ok = _import_table_ods($dbh, $table, $frameworkcode, $dom, $PKArray, \%fields2Delete); + } else { + $ok = _import_table_excel($dbh, $table, $frameworkcode, $dom, $PKArray, \%fields2Delete); + } + if ($ok) { + if (($ok = scalar(keys %fields2Delete)) > 0) { + $query = 'DELETE FROM ' . $table . ' WHERE '; + map {$query .= $_ . '=? AND ';} @$PKArray; + $query = substr($query, 0, -4); + my $sth = $dbh->prepare($query); + for (keys %fields2Delete) { + eval { + $sth->execute(($frameworkcode, split('_', $_))); + }; + } + } + } else { + $ok = -1; + } + return $ok; +}#_import_table + + +# Process the rows of a worksheet and insert/update them in a mysql table. +sub _processRows_Table +{ + my ($dbh, $frameworkcode, $nodeR, $table, $PKArray, $format, $fields2Delete) = @_; + + my $query; + my @fields = (); + my $fields = ''; + my $dataStr = ''; + my $updateStr = ''; + my $j = 0; + my $db_scheme = C4::Context->config("db_scheme"); + my $ok = 0; + my @fieldsPK = @$PKArray; + shift @fieldsPK; + while ($nodeR) { + if ($nodeR->nodeType == 1 && (($format && $format eq 'ods' && $nodeR->nodeName =~ /(?:table:)?table-row/) || ($nodeR->nodeName =~ /(?:ss:)?Row/)) && $nodeR->hasChildNodes()) { + if ($j == 0) { + # Get name columns + _getFields($nodeR, \@fields, $format); + return 0 unless _check_validity_worksheet($dbh, $table, $nodeR, \@fields, $format); + $fields = join(',', @fields); + $dataStr = ''; + map { $dataStr .= '?,';} @fields; + chop($dataStr) if ($dataStr); + $updateStr = ''; + map { $updateStr .= $_ . '=?,';} @fields; + chop($updateStr) if ($updateStr); + } else { + # Get data from row + my ($dataFields, $dataFieldsR) = _getDataFields($frameworkcode, $nodeR, \@fields, $format); + if (scalar(@fields) == scalar(@$dataFieldsR)) { + if ($db_scheme eq 'mysql') { + $query = 'INSERT INTO ' . $table . ' (' . $fields . ') VALUES (' . $dataStr . ') ON DUPLICATE KEY UPDATE ' . $updateStr; + } else { + $query = 'INSERT INTO ' . $table . ' (' . $fields . ') VALUES (' . $dataStr . ')'; + } + eval { + my $sth = $dbh->prepare($query); + if ($db_scheme eq 'mysql') { + $sth->execute((@$dataFieldsR, @$dataFieldsR)); + } else { + $sth->execute(@$dataFieldsR); + } + }; + if ($@) { + unless ($db_scheme eq 'mysql') { + $query = 'UPDATE ' . $table . ' SET ' . $updateStr . ' WHERE '; + map {$query .= $_ . '=? AND ';} @$PKArray; + $query = substr($query, 0, -4); + eval { + my $sth2 = $dbh->prepare($query); + my @dataPK = (); + map {push @dataPK, $dataFields->{$_};} @$PKArray; + $sth2->execute((@$dataFieldsR, @dataPK)); + }; + $ok = 1 unless ($@); + } + $debug and warn "Error _processRows_Table $@\n"; + } else { + $ok = 1; + } + if ($ok) { + my $field = ''; + map { $field .= $dataFields->{$_} . '_'; } @fieldsPK; + chop $field; + delete $fields2Delete->{$field} if (exists($fields2Delete->{$field})); + } + $ok = 0; + } + } + $j++; + } + $nodeR = $nodeR->nextSibling; + } + return 1; +}#_processRows_Table + + +# Import worksheet from the ods content.xml file to the mysql table +sub _import_table_ods +{ + my ($dbh, $table, $frameworkcode, $dom, $PKArray, $fields2Delete) = @_; + + my $xc = XML::LibXML::XPathContext->new($dom); + $xc->registerNs('xmlns:office','urn:oasis:names:tc:opendocument:xmlns:office:1.0'); + $xc->registerNs('xmlns:table','urn:oasis:names:tc:opendocument:xmlns:table:1.0'); + $xc->registerNs('xmlns:text','urn:oasis:names:tc:opendocument:xmlns:text:1.0'); + my @nodes; + @nodes = $xc->findnodes('//table:table[@table:name="' . $table . '"]'); + if (@nodes == 1 && $nodes[0]->hasChildNodes()) { + my $nodeR = $nodes[0]->firstChild; + return _processRows_Table($dbh, $frameworkcode, $nodeR, $table, $PKArray, 'ods', $fields2Delete); + } else { + $debug and warn "Error _import_table_ods there's not worksheet for $table\n"; + } + return 0; +}#_import_table_ods + + +# Import worksheet from the excel-xml file to the mysql table +sub _import_table_excel +{ + my ($dbh, $table, $frameworkcode, $dom, $PKArray, $fields2Delete) = @_; + + my $xc = XML::LibXML::XPathContext->new($dom); + $xc->registerNs('xmlns','urn:schemas-microsoft-com:office:spreadsheet'); + $xc->registerNs('xmlns:ss','urn:schemas-microsoft-com:office:spreadsheet'); + $xc->registerNs('xmlns:x','urn:schemas-microsoft-com:office:excel'); + my @nodes; + @nodes = $xc->findnodes('//ss:Worksheet[@ss:Name="' . $table . '"]'); + if (@nodes > 0) { + for (my $i=0; $i < @nodes; $i++) { + my @nodesT = $nodes[$i]->getElementsByTagNameNS('urn:schemas-microsoft-com:office:spreadsheet', 'Table'); + if (@nodesT == 1 && $nodesT[0]->hasChildNodes()) { + my $nodeR = $nodesT[0]->firstChild; + return _processRows_Table($dbh, $frameworkcode, $nodeR, $table, $PKArray, undef, $fields2Delete); + } + } + } else { + $debug and warn "Error _import_table_excel there's not worksheet for $table\n"; + } + return 0; +}#_import_table_excel + + +# Get the data from a cell on a ods file through the value attribute or the text node +sub _getDataNodeODS +{ + my $node = shift; + + my $data; + my $repeated = 0; + if ($node->nodeType == 1 && $node->nodeName =~ /(?:table:)?table-cell/) { + if ($node->hasAttributeNS('urn:oasis:names:tc:opendocument:xmlns:office:1.0', 'value')) { + $data = $node->getAttributeNS('urn:oasis:names:tc:opendocument:xmlns:office:1.0', 'value'); + } elsif ($node->hasChildNodes()) { + my @nodes2 = $node->getElementsByTagNameNS('urn:oasis:names:tc:opendocument:xmlns:text:1.0', 'p'); + if (@nodes2 == 1 && $nodes2[0]->hasChildNodes()) { + $data = $nodes2[0]->firstChild->nodeValue; + } + } + if ($node->hasAttributeNS('urn:oasis:names:tc:opendocument:xmlns:table:1.0', 'number-columns-repeated')) { + $repeated = $node->getAttributeNS('urn:oasis:names:tc:opendocument:xmlns:table:1.0', 'number-columns-repeated'); + } + } + return ($data, $repeated); +}#_getDataNodeODS + + +# Get the data from a row of a spreadsheet +sub _getDataFields +{ + my ($frameworkcode, $node, $fields, $format) = @_; + + my $dataFields = {}; + my @dataFieldsA = (); + if ($node && $node->hasChildNodes()) { + my $node2 = $node->firstChild; + my ($data, $repeated); + my $i = 0; + my $ok = 0; + $repeated = 0; + while ($node2) { + if ($format && $format eq 'ods') { + ($data, $repeated) = _getDataNodeODS($node2) if ($repeated <= 0); + $repeated--; + $ok = 1 if (defined($data)); + } else { + if ($node2->nodeType == 1 && $node2->nodeName =~ /(?:ss:)?Cell/) { + my @nodes3 = $node2->getElementsByTagNameNS('urn:schemas-microsoft-com:office:spreadsheet', 'Data'); + if (@nodes3 == 1 && $nodes3[0]->hasChildNodes()) { + $data = $nodes3[0]->firstChild->nodeValue; + $ok = 1; + } + } + } + if ($ok) { + $data = '' if ($data eq '#'); + $data = $frameworkcode if ($fields->[$i] eq 'frameworkcode'); + $dataFields->{$fields->[$i]} = $data; + push @dataFieldsA, $data; + $i++; + } + $ok = 0; + $node2 = $node2->nextSibling if ($repeated <= 0); + } + } + return ($dataFields, \@dataFieldsA); +}#_getDataFields + + +# Get the data from the first row to know the column names +sub _getFields +{ + my ($node, $fields, $format) = @_; + + if ($node && $node->hasChildNodes()) { + my $node2 = $node->firstChild; + my ($data, $repeated); + while ($node2) { + if ($format && $format eq 'ods') { + ($data, $repeated) = _getDataNodeODS($node2); + push @$fields, $data if (defined($data)); + } else { + if ($node2->nodeType == 1 && $node2->nodeName =~ /(?:ss:)?Cell/) { + my @nodes3 = $node2->getElementsByTagNameNS('urn:schemas-microsoft-com:office:spreadsheet', 'Data'); + if (@nodes3 == 1 && $nodes3[0]->hasChildNodes()) { + $data = $nodes3[0]->firstChild->nodeValue; + push @$fields, $data; + } + } + } + $node2 = $node2->nextSibling; + } + } +}#_getFields + + + + +1; +__END__ + +=head1 AUTHOR + +Koha Development Team + +=cut + + --- a/admin/import_export_framework.pl +++ a/admin/import_export_framework.pl @@ -0,0 +1,68 @@ +#!/usr/bin/perl + +# Copyright 2010-2011 MASmedios.com y Ministerio de Cultura +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +use strict; +use warnings; +use CGI; +use C4::Context; +use C4::ImportExportFramework; + +my $input = new CGI; + +my $frameworkcode = $input->param('frameworkcode') || ''; +my $action = $input->param('action') || 'export'; + +## Exporting +if ($action eq 'export' && $input->request_method() eq 'GET') { + my $strXml = ''; + ExportFramework($frameworkcode, \$strXml, $input->param('type_export_' . $frameworkcode)); + if ($input->param('type_export_' . $frameworkcode) eq 'excel') { + # Excel-xml file + print $input->header(-type => 'application/excel', -attachment => 'export_' . $frameworkcode . '.xml'); + print $strXml; + } else { + # ODS file + my $strODS = ''; + createODS($strXml, 'en', \$strODS); + print $input->header(-type => 'application/vnd.oasis.opendocument.spreadsheet', -attachment => 'export_' . $frameworkcode . '.ods'); + print $strODS; + } +## Importing +} elsif ($input->request_method() eq 'POST') { + my $ok = -1; + my $fieldname = 'file_import_' . $frameworkcode; + my $filename = $input->param($fieldname); + # upload the input file + if ($filename && $filename =~ /\.(ods|xml)$/i) { + my $extension = $1; + my $uploadFd = $input->upload($fieldname); + if ($uploadFd && !$input->cgi_error) { + my $tmpfilename = $input->tmpFileName($input->param($fieldname)); + $filename = $tmpfilename . '.' . $extension; # rename the tmp file with the extension + $ok = ImportFramework($filename, $frameworkcode, 1) if (rename($tmpfilename, $filename)); + } + } + if ($ok >= 0) { # If everything went ok go to the framework marc structure + print $input->redirect( -location => '/cgi-bin/koha/admin/marctagstructure.pl?frameworkcode=' . $frameworkcode); + } else { + # If something failed go to the list of frameworks and show message + print $input->redirect( -location => '/cgi-bin/koha/admin/biblio_framework.pl?error_import_export=' . $frameworkcode); + } +} --- a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css +++ a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css @@ -1924,3 +1924,51 @@ ul.budget_hierarchy li:first-child:after { margin : 1em 0; } fieldset.rows+h3 {clear:both;padding-top:.5em;} + +.import_export{ + position:relative; +} +.import_export .import_export_options{ + background: white; + border: 1px solid #CDCDCD; + left: 60px; + padding: 10px; + position: absolute; + top: 0; + z-index: 1; + width: 300px; +} +.import_export_options li{ + display: block; + list-style: none; + padding-top: 10px; +} +.import_export_options .import_export_close { + cursor: pointer; + text-decoration: underline; +} +.import_export_options .export_ok { + padding: 10; + background: #E3E3E3 none; + cursor: pointer; + margin-left: 20px; + border: none; +} +.import_export_options .import_ok { + padding: 10; + background: #E3E3E3 none; + cursor: pointer; + margin-left: 20px; + border: none; +} +.form_import .input_import { + border: 1px solid #bcbcbc; +} +.import_export_options .importing { + padding: inherit; + background: none; +} +.li_close_import_export { + text-align: right; +} + --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/biblio_framework.tmpl +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/biblio_framework.tmpl @@ -48,6 +48,88 @@ $(document).ready(function() { }); //]]> + + @@ -115,6 +197,8 @@ $(document).ready(function() {   Edit Delete + Export + Import   @@ -122,6 +206,34 @@ $(document).ready(function() { ">MARC structure     +
framework structure (fields, subfields) to a spreadsheet file (.xml, .ods)">Export +
+
" method="get" target="_blank" class="form_export"> + " /> +
    +
  • Close
  • +
  • " value="excel" id="type_export_" checked="checked" />
  • +
  • " value="ods" id="type_export_" />
  • +
  • +
+
+
+
+ +
framework structure (fields, subfields) from a spreadsheet file (.xml, .ods)">Import +
+
" id="form_i_" method="post" enctype="multipart/form-data" class="form_import"> + " /> + +
    +
  • Close
  • +
  • " id="file_import_" class="input_import" value="" autocomplete="off" />
  • +
  • " style="display:none" class="importing">Importing...
  • +
+
+
+
+ @@ -133,6 +245,35 @@ $(document).ready(function() { " >MARC structure ?op=add_form&frameworkcode=">Edit ?op=delete_confirm&frameworkcode=">Delete + +
framework structure (fields, subfields) to a spreadsheet file (.xml, .ods)">Export +
+
" method="get" target="_blank" class="form_export"> + " /> +
    +
  • Close
  • +
  • " value="excel" id="type_export_" checked="checked" />
  • +
  • " value="ods" id="type_export_" />
  • +
  • +
+
+
+
+ +
framework structure (fields, subfields) from a spreadsheet file (.xml, .ods)">Import +
+
" id="form_i_" method="post" enctype="multipart/form-data" class="form_import"> + " /> + +
    +
  • Close
  • +
  • " id="file_import_" class="input_import" value="" autocomplete="off" />
  • +
  • " style="display:none" class="importing">Importing...
  • +
+
+
+
+ --