从用Perl创建的Excel 2007文件中读取标题行时出现问题

从用Perl创建的Excel 2007文件中读取标题行时出现问题,perl,excel,excel-2007,solaris,Perl,Excel,Excel 2007,Solaris,我在合并两个动态创建的Excel 2007文件时遇到问题。 我的文件是在Solaris上使用Perl模块创建的 假设我有两个文件,fileA.xlsx和fileB.xlsx。现在我想把它们合并在一起(fileA+fileB=>fileC)。 此时,实际上不可能将fileB附加到fileA。这是Excel::Writer::XLSX的一个限制,它只能创建新文件 这两个.xlsx文件都可以在Excel 2007、LibreOffice 3(linux上)和(在Microsoft的xlsx到xls转换

我在合并两个动态创建的Excel 2007文件时遇到问题。 我的文件是在Solaris上使用Perl模块创建的

假设我有两个文件,fileA.xlsx和fileB.xlsx。现在我想把它们合并在一起(fileA+fileB=>fileC)。 此时,实际上不可能将fileB附加到fileA。这是Excel::Writer::XLSX的一个限制,它只能创建新文件

这两个.xlsx文件都可以在Excel 2007、LibreOffice 3(linux上)和(在Microsoft的xlsx到xls转换器的帮助下)甚至在Excel 2003中打开而不必抱怨

但是,当我用perl打开它们时(使用模块电子表格::XLSX),标题行(第0行)的内容总是被跳过

# ...
foreach my $infile (@infiles) {
    my $excel = Spreadsheet::XLSX->new($infile);
    my $i     = 0;

    foreach my $sheet ( @{ $excel->{Worksheet} } ) {

        printf( "Infile '$infile', Sheet $i: %s\n", $sheet->{Name} );

        $sheet->{MaxRow} ||= $sheet->{MinRow};

        print "$infile: " . $sheet->{MaxRow} . " rows\n";
        print "data starts at row: " . $sheet->{MinRow} . ". \n";

        next unless $i == 0;    # only copy data from the first sheet (for speed)
        my $start_row = $sheet->{MinRow};

        foreach my $row ( $start_row .. $sheet->{MaxRow} ) {

            $sheet->{MaxCol} ||= $sheet->{MinCol};
           foreach my $col ( $sheet->{MinCol} .. $sheet->{MaxCol} ) {
              my $cell = $sheet->{Cells}[$row][$col];

              if ($cell) {

              # do something with the data
              # ...
              # write to outfile
              $excel_writer->sheets(0)->write($dest_row, $col, $cell->{Val} )
              }
           }

        }
  }
}
现在,这个代码片段的输出总是

data starts at row: 1. 
但事实并非如此,它从第0行开始。若我手动从第0行读取数据,$cell是未定义的(尽管它不应该是)

有趣的是,当我在MicrosoftExcel中打开文件,并对其进行简单的更改(例如,在标题行中的一个单元格值上添加一个空格)并保存文件时,上面的代码会找到标题行

data starts at row: 0. 
顺便说一句,当我在LibreOffice中打开、更改、保存文件时,当我用上面的代码重新读取日期值时,会出现许多关于日期值的警告。(因此,LibreOffice保存的日期时间值似乎有点不正确)

生成文件的代码如下所示(注意:某些变量是在此子类之外定义的):

子导出asxls{
#需要电子表格::WriteExcel;
需要Excel::Writer::XLSX;
我的($data,$dir,$sep,@not2export)=@;
我的$val;
我的$EXCEL\u MAXROW=1048576;
返回undef,除非$data;
返回“.”,除非标量@$data>0;
my$time=time2str(“%Y%m%d_%H%m%S”,time());
my$file=“$outdir/$dir/${host}{port}-${time}.xlsx”;
#my$workbook=电子表格::WriteExcel->新建($file);
my$workbook=Excel::Writer::XLSX->新建($file);
$workbook->set_optimization();
我的$工作表=$工作簿->添加工作表();
#设置日期的默认格式。
#my$date_formatHMS=$workbook->add_format(num_format=>'mmm d yyyy hh:mm AM/PM');
#my$date_formatHMS=$workbook->add_format(num_format=>'yyyy-mm-ddThh:mm:ss.sss');
我的%格式;
$formats{date\u HM}=$workbook->add\u格式(num\u格式=>'yyyy-mm-ddThh:mm');
$formats{date\u HMS}=$workbook->add\u格式(num\u格式=>'yyyy-mm-ddThh:mm:ss');
$formats{num}=$workbook->add_format();
$formats{num}->set_num_format();
$formats{headline}=$workbook->add_format();
$formats{headline}->set_bold();
$formats{headline}->set_num_格式('@');
#格式为字符串。使用Excel文本格式@:
#编辑时不更改为数字
$formats{string}=$workbook->add_format(num_format=>'@');
$worksheet->set_行(0,15,$formats{headline});
我的$row=0;
我的$col=0;
对于(my$r=-1;$r<@$data&&r<$EXCEL\u MAXROW;$r++){
对于(我的$i=0;$i<@$column;$i++){
下一个if grep($\ueq$列->[$i],@not2export);
my$val=$data->[$r]{$column->[$i]};
my$t=int$type->[$i];
如果($r<0){
#警告“类型:$type->[$i],”;
#Erste Zeile=斯帕尔滕纳曼·奥斯格本
$worksheet->write_string($row,$col++,$column->[$i],$formats{string});
#$worksheet->write_comment(0,0,“\x{263a}”);#Smiley
#$worksheet->write($row,$col++,$column->[$i],$formats{headline});
}elsif($t==11)或($t==9)){
#11-Der Wert ist ein数据,im短格式,9长
$val=time2str(“%Y-%m-%dT%H:%m:%S”),str2time($data->[$r]{$column->[$i]});
$worksheet->write_date_time($row,$col++,$val,$formats{date_HMS});
}否则{
$worksheet->write($row、$col++、$val);
}
}
$col=0;
$row++;
}
返回$file;
}

这些文件之间的区别如下。

左边是Excel::Writer::XLSX生成的文件。右边是MS Excel 2003在对标题行进行微小更改后生成的文件。行标题数据被重构,外部化到另一个文件sharedStrings.xml中

看起来像这样

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="5" uniqueCount="5">
  <si>
    <t>SITE</t>
  </si>
  <si>
    <t>LOG_DATE</t>
  </si>
  <si>
    <t>KTZI201_WF_TEMPERATUR</t>
  </si>
  <si>
    <t>KTZI300_TEMP_RESERVOIR</t>
  </si>
  <si>
    <t>XPEDITION</t>
  </si>
</sst>

场地
日志日期
KTZI201华氏温度
KTZI300_温度_蓄水池
XPEDITION

如果.XLSX文件的格式如图片右半部分所示,则电子表格::XLSX可以读取标题,但如果格式如左半部分所示,则跳过标题行。

当我针对此Excel::Writer::XLSX的输出运行程序时,它会正确报告第一行中的数据(行==0):

也许您应该仔细检查生成输入文件的程序


另外,请确保您使用的是最新版本的。

注意,这不是原因:您正在设置
$i=0
,但在循环过程中没有更改值,因此您总是在执行循环的其余部分。@ott:您是对的。但$i在这里确实无关紧要。实际上,我在我真正的脚本代码的底部增加了它。为了简洁起见,我在这里手工添加了四个结束参数。似乎是E::W::X中的
set\u optimization()
导致了这个问题。我必须进一步研究一下,看看确切的原因是什么。更新:看起来电子表格::XLSX没有读取E::W:X在优化模式下写入的inlineStr字符串。谢谢,John,我添加了生成Excel文件的代码。它可能不会按原样编译,因为有些变量是在子类之外定义的。但是,也许您只需查看源代码就可以发现问题。我使用的是你们模块的v0.47,顺便说一句,这太棒了。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="5" uniqueCount="5">
  <si>
    <t>SITE</t>
  </si>
  <si>
    <t>LOG_DATE</t>
  </si>
  <si>
    <t>KTZI201_WF_TEMPERATUR</t>
  </si>
  <si>
    <t>KTZI300_TEMP_RESERVOIR</t>
  </si>
  <si>
    <t>XPEDITION</t>
  </si>
</sst>
Infile 'a_simple.xlsx', Sheet 0: Sheet1
a_simple.xlsx: 10 rows
data starts at row: 0.