Perl 对于大型XML,Simple返回“内存不足”错误

Perl 对于大型XML,Simple返回“内存不足”错误,perl,xml-parsing,xml-simple,Perl,Xml Parsing,Xml Simple,这可能需要一些时间来解释,但我有一个文件xmlsist.txt,其中包含指向多个IDOC XML的路径。XMLList.txt的内容如下所示: /usr/local/sterlingcommerce/data/archive/SFGprdr/SFTPGET/2017/Dec/week_4/AU_DHL_PW_Inbound_Delivery_Pfizer_20171220071754.xml /usr/local/sterlingcommerce/data/archive/SFGprdr/SFT

这可能需要一些时间来解释,但我有一个文件xmlsist.txt,其中包含指向多个IDOC XML的路径。XMLList.txt的内容如下所示:

/usr/local/sterlingcommerce/data/archive/SFGprdr/SFTPGET/2017/Dec/week_4/AU_DHL_PW_Inbound_Delivery_Pfizer_20171220071754.xml /usr/local/sterlingcommerce/data/archive/SFGprdr/SFTPGET/2017/Dec/week_4/AU_DHL_PW_Inbound_Delivery_Pfizer_20171220083310.xml /usr/local/sterlingcommerce/data/archive/SFGprdr/SFTPGET/2017/Dec/week_4/ccmasout_MQ_GLB_1_20171220154826.xml

我试图创建一个Perl脚本,读取每个XML,并将每个XML文件中的标记DOCNUM、SNDPRN和RCVPRN的值解析为管道分隔的文件report.csv

另外需要注意的是,我的XML文件可能是: 全部在一行上-示例

EDI_DC40400 000000044347488673130 14德尔夫里07 ZDELVRY073PLZIBADVIBG SAPQ01LSQ01CLNT400 XMLDIST_MTLSLS 敦豪。。。。 或多行XML:

0000000658056255 发票02 发票 SAP01 ALE400 XML发票 库 C18BASWARE 20171220 222323 到目前为止,我使用的脚本似乎适用于小型XML。但是,某些大于50 MB的XML会引发此错误:

内存不足!内存不足!在退出时调用了回调 /usr/opt/perl5/lib/site_perl/5.10.1/XML/SAX/Base.pm 第1941行1 F通过call_sv从外部包调用的子例程 通过调用exit退出

内存不足

这是我使用的代码。希望您能帮助调整此选项:

#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;
# use module
use XML::Simple;
use Data::Dumper;

# create object
my $xml = new XML::Simple; 

my $file_list = 'XMLList.txt';
open(my $fh_i, '<:encoding(UTF-8)', $file_list)
  or die "Could not open file '$file_list' $!";

my $csv_out = 'report.csv';
open(my $fh_o, '>', $csv_out)
  or die "Could not open file '$csv_out' $!"; 

while (my $row = <$fh_i>) {
  $row =~ s/\R//g;
  my $data = $xml->XMLin($row);
  print $fh_o "$data->{IDOC}->{EDI_DC40}->{DOCNUM}|";
  print $fh_o "$data->{IDOC}->{EDI_DC40}->{SNDPRN}|";
  print $fh_o "$data->{IDOC}->{EDI_DC40}->{RCVPRN}\n";
}

close $fh_o;

首先,如果文件包含换行符

  while (my $row = <$fh_i>){
  $row =~ s/\R//g;
  my $data = $xml->XMLin($row);

将从文件中一次读取一行,并尝试仅在该行而不是整个文档上执行XML转换。我建议您将每个文件放入缓冲区,并在XMLin转换之前使用正则表达式消除换行符和回车符。此外,如果文件中有任何XML错误,XMLin将不规则地消失,因此您希望在eval块中运行它。

我建议人们在使用XML::Simple时停止使用它。该模块很好地开始了,但它并不意味着是一个长期的解决方案。即使如此,你看

Twig是我经常用于这些任务的工具。您可以为标记设置处理程序并获取树的该部分。你处理它,然后继续前进。这可能像下面这样简单,我设置了一个子例程来处理遇到的每个EDI_DC40:

使用Text::csvxs; 使用XML::Twig; my$csv=Text::csv_XS->new; my$twig=XML::twig->new 小枝处理程序=>{ “EDI\U DC40”=>\&过程EDI\U DC40, }, ; $twig->parsefile$ARGV[0]; 子流程\u EDI\u DC40{ 我的$twig,$thingy=@; 我的@values=map{$thingy->first\u child$\->text} qwDOCNUM RCVPRN SNDPRN; $csv->say*STDOUT,\@value; }
如果我需要处理不适合内存的文档,我会使用XML::LibXML::Reader及其copyCurrentNode1或使用Twig_根的XML::Twig。我不知道在同一对象上多次调用XMLin时,XML::Simple会做什么。但是,在调用XMLin之前将$xml=xml::Simple->new移动到while循环中,您可能会获得一些好处。