【问题标题】:"Out of memory" while parsing large (100 Mb) XML file using perl使用 perl 解析大型(100 Mb)XML 文件时出现“内存不足”
【发布时间】:2011-12-18 17:46:26
【问题描述】:

解析大型 (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;
}

我能做些什么来解决这个错误问题?

【问题讨论】:

  • 对于大型 XML 文件,您应该依赖面向事件的解析器,例如 SAX。不知道perl,不知道有没有类似的?
  • 我不知道这个模块,但是在CPAN 上他们确实提到了如何处理小文件和大文件,而你在这里拥有的是“小”版本。所以也许你可以让你的代码适应“巨大”的实现。
  • @Rubens - 请参阅下面的优秀答案,但简短的版本是“毫无疑问,Perl 有 SAX 解析器”。

标签: xml perl xml-twig


【解决方案1】:

处理无法放入内存的大型 XML 文件是 XML::Twig advertises:

XML::Twig 的优势之一是它可以让您处理文件 不适合内存的(顺便说一句,将 XML 文档存储在内存中作为 树非常消耗内存,扩展因子通常是 10 左右)。

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


问题中发布的代码根本没有利用XML::Twig 的优势(使用simplify 方法并不比XML::Simple 好多少)。

代码中缺少的是“twig_handlers”或“twig_roots”,它们实质上会导致解析器高效地专注于 XML 文档的相关部分。

如果没有看到 XML,很难说 processing the document chunk-by-chunkjust selected parts 是要走的路,但任何一个都应该解决这个问题。

所以代码应该如下所示(逐块演示):

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;

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-25
      • 2014-05-10
      • 2013-06-19
      • 2014-05-24
      • 2019-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多