2011-09-03 26 views
8

Tôi có một lỗi "Hết bộ nhớ" trong khi phân tích lớn (100 Mb) tập tin XML"Hết bộ nhớ" trong khi phân tích lớn (100 Mb) tập tin XML sử dụng perl

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; 
} 

gì tôi có thể làm thế nào để khắc phục vấn đề lỗi này?

+5

Đối với các file XML lớn, bạn nên dựa vào phân tích cú pháp theo định hướng sự kiện, như SAX. Tôi không biết perl, nhưng bạn có biết nếu có cái gì đó tương tự? –

+2

Tôi không biết mô-đun này, nhưng có trên [CPAN] (http://search.cpan.org/perldoc?XML::Twig) họ đề cập đến cách xử lý các tệp nhỏ so với lớn và những gì bạn có ở đây là phiên bản cho "nhỏ". Vì vậy, có lẽ bạn có thể thích ứng với mã của bạn để thực hiện "rất lớn". – TLP

+1

@Rubens - xem câu trả lời tuyệt vời bên dưới, nhưng phiên bản ngắn là "Chắc chắn, Perl có trình phân tích cú pháp SAX". – DVK

Trả lời

18

Xử lý file XML lớn không phù hợp trong bộ nhớ là cái gì đó XML::Twigadvertises:

Một trong những thế mạnh của XML::Twig là nó cho phép bạn làm việc với các tập tin không phù hợp trong bộ nhớ (BTW lưu trữ một tài liệu XML trong bộ nhớ như một cây là khá tốn kém bộ nhớ, yếu tố mở rộng thường là khoảng 10).

Để thực hiện việc này, bạn có thể xác định trình xử lý, sẽ được gọi khi phần tử cụ thể được phân tích cú pháp hoàn toàn. Trong những bộ xử lý, bạn có thể truy cập các yếu tố và xử lý nó như bạn thấy phù hợp (...)


Mã đăng trong câu hỏi không được tận dụng sức mạnh của XML::Twig ở tất cả (sử dụng phương pháp simplify không làm cho nó tốt hơn nhiều so với XML::Simple).

Thiếu mã là 'twig_handlers' hoặc 'twig_roots', về cơ bản khiến trình phân tích cú pháp tập trung vào các phần có liên quan của bộ nhớ tài liệu XML hiệu quả.

Thật khó để nói mà không thấy XML cho dù processing the document chunk-by-chunk hoặc just selected parts là cách để đi, nhưng một trong hai nên giải quyết vấn đề này.

Vì vậy, các mã nên trông giống như sau (đoạn-by-đoạn demo):

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; 
Các vấn đề liên quan