2011-09-03 9 views
8

Tengo un error "Fuera de la memoria" al analizar grande (100 Mb) archivo XML"Memoria insuficiente" al analizar el gran archivo XML (100 Mb) usando 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; 
} 

lo que puedo hacer arreglar este problema de error?

+5

Para archivos grandes XML, debe depender de programas de análisis orientados a eventos, como SAX. No sé perl, pero ¿sabes si hay algo similar? –

+2

No conozco este módulo, pero en [CPAN] (http://search.cpan.org/perldoc?XML::Twig) mencionan cómo manejar archivos pequeños vs enormes, y lo que tiene aquí es el versión para "pequeño". Entonces tal vez puedas adaptar tu código a la implementación "enorme". – TLP

+1

@Rubens - vea debajo respuestas excelentes, pero la versión corta es "Indubitablemente, Perl tiene analizadores SAX". – DVK

Respuesta

18

el manejo de grandes archivos XML que no caben en la memoria es algo que XML::Twigadvertises:

Uno de los puntos fuertes de XML::Twig es que le permiten trabajar con archivos que no caben en la memoria (BTW el almacenamiento de un documento XML en la memoria como un árbol es bastante caro para la memoria, el factor de expansión suele ser alrededor de 10).

Para hacer esto, puede definir manejadores, que serán llamados una vez que un elemento específico ha sido completamente analizado. En estos controladores puede el acceso al elemento y procesarlo como mejor le parezca (...)


El código publicado en la pregunta no está haciendo uso de la fuerza de XML::Twig en absoluto (usando el método simplify no lo hace mucho mejor que XML::Simple).

Lo que falta en el código es 'twig_handlers' o 'twig_roots', que esencialmente hacen que el analizador se centre de manera eficiente en partes relevantes de la memoria del documento XML.

Es difícil decir sin ver el XML si processing the document chunk-by-chunk o es el camino a seguir, pero cualquiera de los dos debe resolver este problema.

Así que el código debe ser algo como lo siguiente (demo trozo por trozo):

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; 
Cuestiones relacionadas