Возможно ли, в Ruby, иметь разбор DOM для частей огромного XML, который иначе анализируется SAX? - PullRequest
0 голосов
/ 03 октября 2018

Мне нужно проанализировать огромный XML-файл (размером 70 ГБ) в Ruby, и в настоящее время я использую синтаксический анализатор SAX от Nokogiri.Этот файл очень большой, но он состоит из одного корневого элемента, а затем содержит множество записей, каждый из которых идеально управляем по размеру.Необходимость выполнять весь синтаксический анализ на основе событий очень сложно.Есть ли способ проанализировать каждую из этих записей как DOM, даже если весь файл проанализирован как SAX?

Например, я думаю о создании dom со всеми start_element и close_elementзвонки и в последнем, когда запись закрыта, возьми этот DOM и сделай там обработку.Конечно, я не первый, кто задумывается о таком решении.

1 Ответ

0 голосов
/ 03 октября 2018

rminner написал здесь

"Лично я думаю, что XML :: DOM не будет правильным решением, если ваш входной XML-файл очень большой. Мой совершенный выбор для анализа XMLXML :: Twig. Я использую его для анализа очень больших файлов, и он делает это быстро с низким использованием памяти. То же самое может применяться к другим модулям, однако я больше всего знаком с XML :: Twig.

"Я кратко описал, как вы можете выполнить синтаксический анализ с XML :: Twig.Поскольку я точно не знаю, что вы собираетесь делать, я добавил несколько примеров вызовов методов, чтобы вы могли выбрать правильный путь (на случай, если вы когда-нибудь решите его использовать). "

use strict;
use warnings;
use Data::Dumper;
#use Data::Dumper::Concise; # i prefer Data::Dumper::Concise
use XML::Twig;

# individually process each <signal> element
sub signal_handler {
        my ($data, $twig, $elem) = @_;

        # get the attributes of $elem (<signal>)
        my $atts = $elem->atts();  

        if ($atts->{'sigid'} == 3464) {
                print "Found <signal> with sigid == 3464:\n",$elem->sp
+rint(),"\n";
                print "<PRESS ENTER TO CONTINUE>";<STDIN>;
        }

        # if you want to access the element in a way similar to XML::S
+imple:
        my $xml_simple_style_elem = $elem->simplify();

        # check out the simplified structure:
        print Dumper($xml_simple_style_elem);
        print "<PRESS ENTER TO CONTINUE>";<STDIN>;

        # Example for Data Collection:
        my ($sigid, $id) = @{$atts}{qw/sigid id/};
        if (defined $sigid and defined $id) {
                $data->{sigid_id_count}{$sigid}{$id}++;
        }

        # get all elements below <signal> which are called <foo>
        my @foo_subelements  = $elem->descendants('foo');

        $twig->purge; # explicitly free the memory
};

sub main {
        my $fn = shift @ARGV;
        my %collected_data;

        my $twig = XML::Twig->new(
                twig_roots => {
                        'signal'     =>  sub {signal_handler(\%collect
+ed_data, @_);},
                },
        );
        eval {
                $twig->parsefile($fn);
        };
        if ($@) {
                print STDERR "Failed to parse '$fn' ($@)\n";
        }
        if (%collected_data) {
                print "I collected the following data:\n",Dumper(\%col
+lected_data);
        }
}
main();

Пожалуйста, нажмите здесь для получения полной документации

...