当标签(节点)包含前缀时,使用 perl XML::Twig 处理程序从 Excel XML 文件中提取数据

Extracting data from Excel XML files using perl XML::Twig handlers when tags (nodes) contain prefix

我使用 XML::Twig handlers/roots 从大型 XML 文件中提取信息,因为将整个文件加载到内存中的成本太高。这些 XML 文件是 Excel .xlsx 文件的内部 sheet 文件。

到目前为止,这种方法一直运行良好。下面是从内部 XML 文件 sheet1.xml.

中提取所有单元格引用的示例
use strict;
use warnings;
use Archive::Zip qw(:ERROR_CODES :CONSTANTS);
use XML::Twig;
use Data::Dumper;

my $zipName='TestFile.xlsx';
my $zip = Archive::Zip->new();
my $zipread;
$zipread=$zip->read($zipName);

my $tw1=new XML::Twig();
my $fileToAnalyse='xl/worksheets/sheet1.xml';
my $sheetFile = $zip->contents($fileToAnalyse);
    
    
my @Results;
my $t= XML::Twig->new(twig_roots => {'worksheet/sheetData/row/c' => 
                  sub { Get_Sheet_Data_TEST_1(@_,\@Results);}})->parse($sheetFile);
print Dumper \@Results;

sub Get_Sheet_Data_TEST_1{
    my($t,$elt,$Results)= @_;

    my @attrib_NAMES=$elt->att_names();
    for my $attrib_loop (0 .. scalar @attrib_NAMES-1){
        if($attrib_NAMES[$attrib_loop] eq 'r'){
            push @$Results,$elt->att($attrib_NAMES[$attrib_loop]);
        }
    }   
    $t->purge; # frees the memory
}

有时这些文件有我要查找的标签的前缀

所以

'worksheet/sheetData/row/c'

变成

'x:worksheet/x:sheetData/x:row/x:c'

现在我的处理程序永远不会触发,因为它找不到所需的标签。

有什么方法可以修改我的处理程序,而不用硬编码所有可能的前缀可能性,以便可以匹配这些前缀以及没有前缀的“普通”标签?

也许有一种方法可以提前找到任何给定文件使用了哪些前缀,并将这些值设置为一个变量,然后我可以将该变量传递给我的处理程序。

好的,我找到了解决方案。结果 XML::Twig 有一个可选参数

map_xmlns

我可以用它来解决我的问题。所以,我的原始代码

my $t= XML::Twig->new(twig_roots => {'worksheet/sheetData/row/c' => 
         sub { Get_Sheet_Data_TEST_1(@_,\@Results);}})->parse($sheetFile);

变成

my $t= XML::Twig->new(
map_xmlns => {
        'http://schemas.openxmlformats.org/spreadsheetml/2006/main' => 's'},
twig_roots => {'s:worksheet/s:sheetData/s:row/s:c' => 
       sub { Get_Sheet_Data_TEST_1(@_,\@Results);}})->parse($sheetFile);

现在我的处理程序适用于所有前缀(甚至是空前缀!)。

如 XML::Twig 文档中所写:

map_xmlns

向此选项传递一个将 uri 映射到前缀的 hashref。文档中的前缀将替换为地图中的前缀。映射的前缀可以(实际上必须)用于触发处理程序、导航或查询文档。