我怎样才能加速XML :: Twig

use*_*691 5 xml perl parsing large-files xml-twig

XML::Twig用来解析一个非常大的XML文档.我想根据<change></change>标签将其拆分为块.

现在我有:

my $xml = XML::Twig->new(twig_handlers => { 'change' => \&parseChange, });
$xml->parsefile($LOGFILE);

sub parseChange {

  my ($xml, $change) = @_;

  my $message = $change->first_child('message');
  my @lines   = $message->children_text('line');

  foreach (@lines) {
    if ($_ =~ /[^a-zA-Z0-9](?i)bug(?-i)[^a-zA-Z0-9]/) {
      print outputData "$_\n";
    }
  }

  outputData->flush();
  $change->purge;
}
Run Code Online (Sandbox Code Playgroud)

现在,parseChange当它从XML中提取该块时,它正在运行该方法.它变得非常缓慢.我测试它反对从一个文件中读取XML $/=</change>并编写一个函数来返回XML标记的内容,它的速度要快得多.

有什么东西我缺少或我使用XML::Twig不正确吗?我是Perl的新手.

编辑:以下是更改文件的示例更改.该文件由很多这些文件一个接一个地组成,它们之间不应该有任何东西:

<change>
<project>device_common</project>
<commit_hash>523e077fb8fe899680c33539155d935e0624e40a</commit_hash>
<tree_hash>598e7a1bd070f33b1f1f8c926047edde055094cf</tree_hash>      
<parent_hashes>71b1f9be815b72f925e66e866cb7afe9c5cd3239</parent_hashes>      
<author_name>Jean-Baptiste Queru</author_name>      
<author_e-mail>jbq@google.com</author_e-mail>      
<author_date>Fri Apr 22 08:32:04 2011 -0700</author_date>      
<commiter_name>Jean-Baptiste Queru</commiter_name>      
<commiter_email>jbq@google.com</commiter_email>      
<committer_date>Fri Apr 22 08:32:04 2011 -0700</committer_date>      
<subject>chmod the output scripts</subject>      
<message>         
    <line>Change-Id: Iae22c67066ba4160071aa2b30a5a1052b00a9d7f</line>      
</message>      
<target>         
    <line>generate-blob-scripts.sh</line>      
</target>   
</change>
Run Code Online (Sandbox Code Playgroud)

dan*_*111 1

XML::Twig包括一种机制,您可以通过该机制在标签出现时对其进行处理,然后丢弃不再需要的内容以释放内存。

这是取自文档的示例(其中还有更多有用的信息):

my $t= XML::Twig->new( twig_handlers => 
                          { section => \&section,
                            para   => sub { $_->set_tag( 'p'); }
                          },
                       );
  $t->parsefile( 'doc.xml');

  # the handler is called once a section is completely parsed, ie when 
  # the end tag for section is found, it receives the twig itself and
  # the element (including all its sub-elements) as arguments
  sub section 
    { my( $t, $section)= @_;      # arguments for all twig_handlers
      $section->set_tag( 'div');  # change the tag name.4, my favourite method...
      # let's use the attribute nb as a prefix to the title
      my $title= $section->first_child( 'title'); # find the title
      my $nb= $title->att( 'nb'); # get the attribute
      $title->prefix( "$nb - ");  # easy isn't it?
      $section->flush;            # outputs the section and frees memory
    }
Run Code Online (Sandbox Code Playgroud)

在处理多 GB 文件时,这可能是必不可少的,因为(再次根据文档)将整个内容存储在内存中可能需要文件大小的 10 倍之多。

编辑:根据您编辑的问题提出一些评论。在不了解更多关于文件结构的情况下,尚不清楚究竟是什么减慢了您的速度,但这里有一些可以尝试的事情:

  • 如果您要写入很多行,刷新输出文件句柄会减慢您的速度。Perl 出于性能原因专门缓存文件写入,而您正在绕过它。
  • 为什么不使用该(?i)机制(一种可能会降低性能的相当高级的功能),使整个匹配不区分大小写呢?/[^a-z0-9]bug[^a-z0-9]/i是等价的。您还可以使用 来简化它/\bbug\b/i,这几乎是等效的,唯一的区别是下划线包含在不匹配的类中。
  • 还可以进行其他一些简化来删除中间步骤。

这个处理程序代码与您的速度相比如何?

sub parseChange
{
    my ($xml, $change) = @_;

    foreach(grep /[^a-z0-9]bug[^a-z0-9]/i, $change->first_child_text('message'))
    {
        print outputData "$_\n";
    }

    $change->purge;
}
Run Code Online (Sandbox Code Playgroud)