2011-09-03 7 views
8

ho un errore "Memoria insufficiente" durante l'analisi di grandi dimensioni (100 Mb) file XML"Memoria insufficiente" durante l'analisi di grandi dimensioni (100 Mb) file XML utilizzando 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; 
} 

Cosa posso fare risolvere questo problema di errore?

+5

Per i grandi file XML, si dovrebbe fare affidamento su parser orientata evento, come SAX. Non lo so perl, ma sai se c'è qualcosa di simile? –

+2

Non conosco questo modulo, ma lì su [CPAN] (http://search.cpan.org/perldoc?XML::Twig) loro menzionano come gestire file piccoli o enormi, e quello che hai qui è il versione per "piccolo". Quindi forse potresti adattare il tuo codice all'implementazione "enorme". – TLP

+1

@Rubens - vedi sotto le risposte eccellenti, ma la versione breve è "Indubbiamente, Perl ha parser SAX". – DVK

risposta

18

gestione di grandi file XML che non rientrano nella memoria è qualcosa che XML::Twigadvertises:

Uno dei punti di forza di XML::Twig è che consentono di lavorare con i file che non rientrano nella memoria (BTW la memorizzazione di un documento XML in memoria come albero è abbastanza costosa in memoria, il fattore di espansione spesso è pari a circa 10).

Per fare ciò è possibile definire i gestori, che verranno chiamati una volta che un elemento specifico è stato completamente analizzato. In questi gestori è possibile accesso l'elemento e il processo come si vede in forma (...)


Il codice scritto nella questione non sta facendo uso della forza della XML::Twig a tutti (utilizzando il metodo simplify non lo rende molto meglio di XML::Simple).

Ciò che manca dal codice sono "twig_handlers" o "twig_roots", che essenzialmente fanno sì che il parser si concentri in modo efficiente su porzioni rilevanti della memoria del documento XML.

È difficile dire senza vedere l'XML se processing the document chunk-by-chunk o just selected parts è la strada da percorrere, ma entrambi dovrebbero risolvere questo problema.

Così il codice dovrebbe essere simile alla seguente (demo 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; 
Problemi correlati