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)
XML::Twig包括一种机制,您可以通过该机制在标签出现时对其进行处理,然后丢弃不再需要的内容以释放内存。
这是取自文档的示例(其中还有更多有用的信息):
my $t= XML::Twig->new( twig_handlers =>
{ section => \§ion,
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 倍之多。
编辑:根据您编辑的问题提出一些评论。在不了解更多关于文件结构的情况下,尚不清楚究竟是什么减慢了您的速度,但这里有一些可以尝试的事情:
(?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)