Как сгладить / перекомпилировать электронную таблицу Excel с помощью sheetjs или exceljs при записи

Мы используем excel в качестве файла конфигурации для клиентов. Однако наши процессы работают только на серверах Linux. Нам нужно взять мастер-файл, обновить все клиентские книги новой информацией и зафиксировать в GitLab. Затем пользователи проверяют его, добавляют свои изменения, фиксируют обратно в GitLab, и процесс продвигает книгу на Сервер A.

Этот процесс отлично работает с nodeJS (exceljs)

Другой процесс на другом сервере использует perl для получения книги, а затем сохраняет каждый лист как файл csv.

Проблема в том, что записываются данные из ОРИГИНАЛЬНОГО рабочего листа, а не обновленные изменения. Это верно как для perl, так и для nodejs. Код для perl и nodejs xlsx to csv находится в конце сообщения.

Испытанные модули: perl: Spreadsheet :: ParseExcel; Таблица :: XLSX; nodejs: node-xlsx, exceljs

Я предполагаю, что это связано с тем, что Microsoft использует XML внутри оболочки excel, она сохраняет старую версию в качестве истории, и поскольку это было исходное имя листа, оно извлекается вместо последней обновленной версии.

Когда я вручную открываю в Excel, все правильно с новой информацией, как и ожидалось.

Когда я использую «Сохранить как ...» вместо «Сохранить», процесс perl может правильно записать обновленный рабочий лист как csv. Таким образом, наш обходной путь заключается в том, чтобы пользователи всегда сохраняли как ... перед внесением дополнительных изменений в GitLab. Мы хотели бы полагаться на обучение, но огромное количество пользователей и клиентов делает надежду, что пользователь сохранит AS ... нецелесообразно.

Есть ли способ воспроизвести «Сохранить как ...» во время моего продвижения на сервер A или, по крайней мере, определить, правильно ли был сохранен файл? Я хотел бы придерживаться excelJS, но я буду использовать все необходимое для репликации Save as ..., который, кажется, перекомпилирует книгу.

В дополнение к nodejs я могу использовать perl, python, ruby ​​- все, что потребуется - чтобы убедиться, что процесс создания csv улавливает новые изменения.

Спасибо за ваше время и помощь.

#!/usr/bin/env perl 
    
     use strict; 
     use warnings; 
     use Carp; 
     use Getopt::Long; 
     use Pod::Usage; 
     use File::Basename qw/fileparse/; 
     use File::Spec; 
     use Spreadsheet::ParseExcel; 
     use Spreadsheet::XLSX; 
     use Getopt::Std;
       
     my %args = (); 
     my $help = undef; 
     GetOptions( 
     \%args, 
     'excel=s', 
     'sheet=s', 
     'man|help'=>\$help, 
     ) or die pod2usage(1); 
      
     pod2usage(1) if $help; 
     pod2usage(-verbose=>2, exitstatus=>0, output=>\*STDOUT) unless $args{excel} || $args{sheet}; 
     
     pod2usage(3) if $help; 
     pod2usage(-verbose=>2, exitstatus=>3, output=>\*STDOUT) unless $args{excel}; 
     
    
     if (_getSuffix($args{excel}) eq ".xls") { 
     my $file = File::Spec->rel2abs($args{excel}); 
      
     if (-e $file) { 
     print _XLS(file=>$file, sheet=>$args{sheet}); 
     } else { 
     exit 1;
     die "Error: Can not find excel file. Please check for exact excel file name and location. \nError: This Program is CASE SENSITIVE. \n"; 
     } 
     } 
     elsif (_getSuffix($args{excel}) eq ".xlsx") { 
     my $file = File::Spec->rel2abs($args{excel}); 
     
     
     if (-e $file) { 
      print _XLSX(file=>$file, sheet=>$args{sheet});
     } 
     else { 
     exit 1;
     die "\nError: Can not find excel file. Please check for exact excel file name and location. \nError: This Program is CASE SENSITIVE.\n"; 
     }
     } 
     else { 
     exit 5; 
     }
      
      
     sub _XLS { 
     my %opts = ( 
     file => undef, 
     sheet => undef, 
     @_, 
     ); 
      
     my $aggregated = (); 
     my $parser = Spreadsheet::ParseExcel->new(); 
     my $workbook = $parser->parse($opts{file}); 
      
     if (!defined $workbook) { 
     exit 3;
     croak "Error: Workbook not found"; 
     } 
      
     foreach my $worksheet ($workbook->worksheet($opts{sheet})) { 
     
     if (!defined $worksheet) { 
       exit 2;
       croak "\nError: Worksheet name doesn't exist in the Excel File. Please check the WorkSheet Name. \nError: This program is CASE SENSITIVE.\n\n";
     }
     
     my ($row_min, $row_max) = $worksheet->row_range(); 
     my ($col_min, $col_max) = $worksheet->col_range(); 
    
     foreach my $row ($row_min .. $row_max){ 
     foreach my $col ($col_min .. $col_max){ 
     my $cell = $worksheet->get_cell($row, $col); 
     if ($cell) {
         $aggregated .= $cell->value().','; 
     }
     else {
         $aggregated .= ',';
     }
     }
     $aggregated .= "\n"; 
     } 
     } 
     return $aggregated; 
     } 
      
      
      
     sub _XLSX { 
     eval {
     my %opts = ( 
     file => undef, 
     sheet => undef, 
     @_,
     ); 
    
      
     my $aggregated_x = (); 
     my $excel = Spreadsheet::XLSX->new($opts{file}); 
      
    foreach my $sheet ($excel->worksheet($opts{sheet})) {
    
        if (!defined $sheet) { 
          exit 2;
          croak "Error: WorkSheet not found"; 
        } 
    
     if ( $sheet->{Name} eq $opts{sheet}) { 
            $sheet->{MaxRow} ||= $sheet->{MinRow}; 
            foreach my $row ($sheet->{MinRow} .. $sheet->{MaxRow}) { 
                    $sheet->{MaxCol} ||= $sheet->{MinCol}; 
                            foreach my $col ($sheet->{MinCol} .. $sheet->{MaxCol}) { 
                            my $cell = $sheet->{Cells}->[$row]->[$col]; 
                            if ($cell) {
                            $aggregated_x .= $cell->{Val}.','; 
                            }
                            else {
                                    $aggregated_x .= ',';
                            } 
                    }
             $aggregated_x .=  "\n"; 
            } 
     }
     } 
     return $aggregated_x; 
     } 
     
     };
     if ($@) {
     exit 3;
     }
     
     
     sub _getSuffix { 
     my $f = shift; 
     my ($basename, $dirname, $ext) = fileparse($f, qr/\.[^\.]*$/); 
     return $ext; 
     }
     
     
     
      sub _convertlwr{ 
      my $f = shift; 
      my ($basename, $dirname, $ext) = fileparse($f, qr/\.[^\.]*$/); 
      return $ext; 
      }
var xlsx = require('node-xlsx')
var fs = require('fs')
var obj = xlsx.parse(__dirname + '/test2.xlsx') // parses a file
var rows = []
var writeStr = ""

//looping through all sheets
for(var i = 0; i < obj.length; i++)
{
    var sheet = obj[i]
    //loop through all rows in the sheet
    for(var j = 0; j < sheet['data'].length; j++)
    {
            //add the row to the rows array
            rows.push(sheet['data'][j])
    }
}

//creates the csv string to write it to a file
for(var i = 0; i < rows.length; i++)
{
    writeStr += rows[i].join(",") + "\n"
}

//writes to a file, but you will presumably send the csv as a      
//response instead
fs.writeFile(__dirname + "/test2.csv", writeStr, function(err) {
    if(err) {
        return console.log(err)
    }
    console.log("test.csv was saved in the current directory!")

person Eric Hansen    schedule 09.09.2020    source источник
comment
Вместо этого сохраните файлы данных в формате CSV, в таком случае сохранение обновит файл CVS.   -  person Polar Bear    schedule 10.09.2020
comment
кажется, есть REST API Excel? docs.microsoft.com/en- нас / sharepoint / dev / general-development /   -  person antont    schedule 10.09.2020
comment
Использует ли ваш текущий процесс на другом сервере perl для получения книги, а затем сохраняет каждый лист как файл csv с использованием любого модуля, такого как Spreadsheet :: ParseExcel и Text :: CSV_XS (для преобразования данных Excel в csv)? Не могли бы вы предоставить дополнительную информацию?   -  person amit bhosale    schedule 10.09.2020
comment
@amitbhosale Я добавил в вопрос код perl. В ответ на ваш вопрос они используют Spreadsheet :: ParseExcel; Таблица :: XLSX;   -  person Eric Hansen    schedule 10.09.2020


Ответы (1)


Ответ невозможен. Чтобы обновить данные внутри книги, которая имеет функции Excel, вы должны открыть ее в Excel, чтобы формулы сработали. Это так просто.

Вы можете разложить книгу на части, создать свои собственные функции javascript, пропустить через нее данные и затем записать их, но существует так много возможных проблем, что это не рекомендуется.

Возможно, однажды Microsoft выпустит Linux API движка Excel для Linux. Но все же маловероятно, что такая вещь будет работать через командную строку без вызова графического интерфейса.

person Eric Hansen    schedule 18.09.2020