使用perl解析大型(100 Mb)XML文件时“内存不足”

时间:2011-09-03 14:22:01

标签: xml perl xml-twig

解析大型(100 Mb)XML文件时出现“内存不足”错误

use strict;
use warnings;
use XML::Twig;

my $twig=XML::Twig->new();
my $data = XML::Twig->new
             ->parsefile("divisionhouserooms-v3.xml")
               ->simplify( keyattr => []);

my @good_division_numbers = qw( 30 31 32 35 38 );

foreach my $property ( @{ $data->{DivisionHouseRoom}}) {

    my $house_code = $property->{HouseCode};
    print $house_code, "\n";

    my $amount_of_bedrooms = 0;

    foreach my $division ( @{ $property->{Divisions}->{Division} } ) {

        next unless grep { $_ eq $division->{DivisionNumber} } @good_division_numbers;
        $amount_of_bedrooms += $division->{DivisionQuantity};
    }

    open my $fh, ">>", "Result.csv" or die $!;
    print $fh join("\t", $house_code, $amount_of_bedrooms), "\n";
    close $fh;
}

我可以采取哪些措施来解决此错误问题?

2 个答案:

答案 0 :(得分:18)

处理不适合内存的大型XML文件是XML::Twig advertises

  

XML::Twig的优点之一是它可以让你使用文件   不适合内存(BTW将XML文档存储在内存中)   树的内存非常昂贵,扩展因素经常出现   大约10)。

     

要执行此操作,您可以定义处理程序,该处理程序将在a之后调用   特定元素已被完全解析。在这些处理程序中,您可以   访问元素并按照您认为合适的方式处理它(...)


问题中发布的代码并未充分利用XML::Twig的强度(使用simplify方法并没有比XML::Simple更好。)< / p>

代码中缺少的是“twig_handlers”或“twig_roots”,这实际上会导致解析器有效地关注XML文档内存的相关部分。

如果没有看到XML,processing the document chunk-by-chunkjust selected parts是否可行,那么很难说,但任何人都应该解决这个问题。

因此代码应该类似于以下内容(chunk-by-chunk演示):

use strict;
use warnings;
use XML::Twig;
use List::Util 'sum';   # To make life easier
use Data::Dump 'dump';  # To see what's going on

my %bedrooms;           # Data structure to store the wanted info

my $xml = XML::Twig->new (
                          twig_roots => {
                                          DivisionHouseRoom => \&count_bedrooms,
                                        }
                         );

$xml->parsefile( 'divisionhouserooms-v3.xml');

sub count_bedrooms {

    my ( $twig, $element ) = @_;

    my @divParents = $element->children( 'Divisions' );
    my $id = $element->first_child_text( 'HouseCode' );

    for my $divParent ( @divParents ) {
        my @divisions = $divParent->children( 'Division' );
        my $total = sum map { $_->text } @divisions;
        $bedrooms{$id} = $total;
    }

    $element->purge;   # Free up memory
}

dump \%bedrooms;

答案 1 :(得分:8)

请参阅Processing an XML document chunk by chunk文档的XML::Twig部分,它专门讨论了如何逐个处理文档,允许进行大型XML文件处理。