2010-08-02 40 views
2

我需要解析幾個大尺寸的XML文件(一個是〜8GB,其他是〜4MB)併合並它們。由於SAX和Tie::File由於記憶和時間問題而不合適,因此我決定嘗試Twig。XML :: Twig能夠從給定的行號開始解析XML文件嗎?

假設每個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}我還需要等待很長一段時間的樹枝開始解析class=english,因爲它需要首先檢查class=math的每一行(如果不需要遍歷每行,請糾正我)。

有什麼辦法讓Twig從行號開始解析,而不是從文件開始?我可以使用grep得到<class name = english>的行號,這個速度要快得多。

在此先感謝。

回答

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); 
+0

非常聰明的解決方案。我會嘗試使用這種方法來查看性能。 – user399517 2010-08-02 20:14:38

1

XML::Twigparse方法接受一個IO::Handle,使你很可能尋求右行自己呢?還有一個input_filter參數的XML::Twig構造函數,您可以跳過第一個n不需要的行。

+0

謝謝zoul。我會嘗試瞭解input_filter的含義 – user399517 2010-08-02 21:22:12