XML :: Twig可以从给定的行号开始解析XML文件吗?

时间:2010-08-02 06:33:54

标签: xml perl xml-twig

我需要解析几个大尺寸的XML文件(一个是大约8GB,其他大约是每个4MB)并合并它们。由于内存和时间问题,SAX和Tie::File都不合适,我决定尝试Twig。

假设每个XML文件由以下几个元素组成:

<class name=math>
     <student>luke1</student>
     ... (a very very long list of student)
   <student>luke8000000</student>
</class>
<class name=english>
   <student>mary1</student>
     ...
   <student>mary1000000</student>
</class>

如您所见,即使我使用TwigRoots => {"class[\@name='english']" => \&counter},我仍需要等待很长时间让Twig开始解析class=english,因为它需要先遍历class=math的每一行(如果不需要越过每一行,请纠正我。)

有没有办法让Twig从行号而不是文件的开头开始解析?我可以使用grep获得<class name = english>的行号,这要快得多。

提前致谢。

2 个答案:

答案 0 :(得分:3)

也许这个例子会给你一些替代策略的想法。特别是,您可以将index_file中的想法与Zoul关于在将文件句柄传递给XML::Twig之前寻找位置的建议相结合。

use strict;
use warnings;

# Index the XML file, storing start and end positions
# for each class in the document. You pay this cost only once.
sub index_file {
    local @ARGV = (shift);
    my (%index, $prev);
    while (<>){
        if ( /^<class name=(\w+)>/ ) {
            my $start = tell() - length();
            $index{$1} = { start => $start, end => undef };

            $index{$prev}{end} = $start - 1 if defined $prev;
            $prev = $1;
        }        
        $index{$prev}{end} = tell if eof;
    }
    return \%index;
}

# Use the index to retrieve the XML for a particular class.
# This allows you to jump quickly to any section of interest.
# It assumes that the sections of the XML document are small enough
# to be held in memory.
sub get_section {
    my ($file_name, $class_name, $index) = @_;
    my $ind = $index->{$class_name};

    open(my $fh, '<', $file_name) or die $!;    
    seek $fh, $ind->{start}, 0;
    read( $fh, my $xml_section, $ind->{end} - $ind->{start} );

    return $xml_section;
}

# Example usage.
sub main {
    my ($file_name) = @_;
    my $index = index_file($file_name);
    for my $cn (keys %$index){
        # Process only sections of interest.
        next unless $cn eq 'math' or $cn eq 'english';
        my $xml = get_section($file_name, $cn, $index);

        # Pass off to XML::Twig or whatever.
        print $xml;
    }
}

main(@ARGV);

答案 1 :(得分:1)

parse的{​​{1}}方法接受XML::Twig,以便您可以自己寻找合适的线路?并且IO::Handle构造函数还有一个input_filter参数,您可以跳过第一个 n 不需要的行。