我需要解析几个大尺寸的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>
的行号,这要快得多。
提前致谢。
答案 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 不需要的行。