Dopo aver incontrato file di dati xml contenenti enormi nodi di testo, ho cercato alcuni modi per leggerli e valutarli nei miei dati script di elaborazione.Modo pratico di leggere xml con enormi nodi di testo in Perl
I file XML sono file di coordinare 3D per la modellazione molecolare applicazioni un hanno questa struttura (esempio):
<?xml version="1.0" encoding="UTF-8"?>
<hoomd_xml version="1.4">
<configuration>
<position>
-0.101000 0.011000 -40.000000
-0.077000 0.008000 -40.469000
-0.008000 0.001000 -40.934000
-0.301000 0.033000 -41.157000
0.213000 -0.023000 -41.348000
...
... 300,000 to 500,000 lines may follow >>
...
-0.140000 0.015000 -42.556000
</position>
<next_huge_section_of_the_same_pattern>
...
...
...
</next_huge_section_of_the_same_pattern>
</configuration>
</hoomd_xml>
Ogni file XML contiene diversi nodi enorme di testo e ha dimensioni comprese tra 60 MB e 100 MB a seconda i contenuti.
Ho provato l'approch Naïve utilizzando XML::Simple primo momento, ma il caricatore avrebbe preso per sempre per analizzare inizialmente il file:
...
my $data = $xml->XMLin('structure_80mb.xml');
...
e fermare con "errore interno: enorme di ricerca di ingresso", quindi questo approccio isn' molto praticabile
Il tentativo successivo è stato quello di utilizzare XML::LibXML per la lettura - ma qui, il caricatore iniziale sarebbe salvare immediatamente con il messaggio di errore "parser di errore: xmlSAX2Characters: enorme nodo di testo".
Befor scrivere su questo argomento su StackOverflow, ho scritto aq & d parser per me e inviato il file attraverso di esso (dopo slurping il file XML MB xx nella scalare $xml
):
...
# read the <position> data from in-memory xml file
my @Coord = xml_parser_hack('position', $xml);
...
che restituisce i dati di ogni riga come un array, completa in pochi secondi e si presenta in questo modo:
sub xml_parser_hack {
my ($tagname, $xml) = @_;
return() unless $xml =~ /^</;
my @Data =();
my ($p0, $p1) = (undef,undef);
$p0 = $+[0] if $xml =~ /^<$tagname[^>]*>[^\r\n]*[r\n]+/msg; # start tag
$p1 = $-[0] if $xml =~ /^<\/$tagname[^>]*>/msg; # end tag
return() unless defined $p0 && defined $p1;
my @Lines = split /[\r\n]+/, substr $xml, $p0, $p1-$p0;
for my $line (@Lines) {
push @Data, [ split /\s+/, $line ];
}
return @Data;
}
questo funziona bene finora, ma non può considerarsi 'pronti per la produzione', naturalmente.
D: Come posso leggere il file utilizzando un modulo Perl? Quale modulo dovrei scegliere?
Grazie in anticipo
rbo
Addendum: dopo aver letto il commento di choroba, ho guardato più in profondità XML :: LibXML. L'apertura del file my $reader = XML::LibXML::Reader->new(location =>'structure_80mb.xml');
funziona, contrariamente a quanto pensavo prima. L'errore si verifica se provo ad accedere al nodo di testo sotto il tag:
...
while ($reader->read) {
# bails out in the loop iteration after accessing the <position> tag,
# if the position's text node is accessed
# -- xmlSAX2Characters: huge text node ---
...
http://search.cpan.org/~mirod/XML-Twig -3.44/Twig.pm - modulo perl per l'elaborazione di enormi documenti XML in modalità albero. –
Come hai aperto il file con XML :: LibXML? Funziona per me per file di 100 MB. – choroba
@choroba - grazie, ho controllato di nuovo - e ho aggiornato l'argomento. –