首页 > 解决方案 > 在 Ruby 中,是否有可能对一个由 SAX 解析的巨大 XML 的一部分进行 DOM 解析?

问题描述

我需要在 Ruby 中解析一个巨大的 XML 文件(70GB 大),目前我正在使用 Nokogiri 的 SAX 解析器。这个文件非常大,但它由一个根元素和许多条目组成,所有这些条目的大小都非常易于管理。必须以基于事件的方式进行所有解析非常困难。即使整个文件被解析为 SAX,有没有办法将这些条目中的每一个解析为 DOM?

例如,我正在考虑使用所有start_elementandclose_element调用构建 dom,在最后一个调用中,当记录关闭时,获取该 DOM 并在那里进行处理。当然,我不是第一个想到这种解决方案的人。

标签: rubyxmldomsax

解决方案


rminner 写在这里

“我个人认为 XML::DOM 不是正确的解决方案,如果您的输入 xml 文件非常大。我解析 xml 的首选选择是 XML::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();

单击此处获取完整文档


推荐阅读