使用PerlXML::LibXML处理XML的速度太慢
XML文件如下所示:使用PerlXML::LibXML处理XML的速度太慢,xml,perl,Xml,Perl,XML文件如下所示: <?xml version="1.0" encoding="UTF-8"?> <resource-data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="resource-data.xsd"> <class name="AP"> <attributes> <resourceI
<?xml version="1.0" encoding="UTF-8"?>
<resource-data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="resource-data.xsd">
<class name="AP">
<attributes>
<resourceId>00 11 B5 1B 6D 20</resourceId>
<lastModifyTime>20130107091545</lastModifyTime>
<dcTime>20130107093019</dcTime>
<attribute name="NMS_ID" value="DNMS" />
<attribute name="IP_ADDR" value="10.11.141.111" />
<attribute name="LABEL_DEV" value="00 11 B5 1B 6D 20" />
</attributes>
<attributes>
<resourceId>00 11 B5 1B 6D 21</resourceId>
<lastModifyTime>20130107091546</lastModifyTime>
<dcTime>20130107093019</dcTime>
<attribute name="NMS_ID" value="DNMS" />
<attribute name="IP_ADDR" value="10.11.141.112" />
<attribute name="LABEL_DEV" value="00 11 B5 1B 6D 21" />
</attributes>
</class>
</resource-data>
我的问题是,如果XML文件只有80MB,那么程序会非常快,但当XML文件大得多时,程序会非常慢。有人能帮我加快速度吗?如果你有这么大的XML文件-80MB+,你无法将整个文件解析到内存中-首先,它非常慢,其次,它最终会耗尽内存,你的程序会崩溃 我建议您使用和使用回调重写代码。使用将允许您在解析过程中处理每个
元素,然后丢弃不再需要的XML数据
这个程序似乎能满足你的需要
use strict;
use warnings;
use XML::Twig;
use Encode;
use constant XML_FILE => 'S:/AP_201301073100_1.xml';
use constant OUT_FILE => 'D:/ap.txt';
open my $outfh, '>:encoding(gbk)', OUT_FILE or die $!;
my $twig = XML::Twig->new(twig_handlers => {attributes => \&attributes});
$twig->parsefile('myxml.xml');
sub attributes {
my ($twig, $atts) = @_;
my @values = map $_->att('value'), $atts->children('attribute');
print $outfh join("\t", @values), "\n";
$twig->purge;
}
输出
DNMS 10.11.141.111 00 11 B5 1B 6D 20
DNMS 10.11.141.112 00 11 B5 1B 6D 21
对于大型XML文件,必须使用基于流的解析器,如,因为DOM解析器在内存中构建整个XML结构。另一种可能性是使用。它的工作原理与SAX类似,但使用与XML::libxml相同的
libxml
库:
#!/usr/bin/perl
use warnings;
use strict;
use XML::LibXML::Reader;
my $reader = XML::LibXML::Reader->new(location => '1.xml');
open my $OUT, '>:encoding(gbk)', '1.out';
while ($reader->read) {
attr($reader) if 'attributes' eq $reader->name
and XML_READER_TYPE_ELEMENT == $reader->nodeType;
}
sub attr {
my $reader = shift;
my @kids;
ATTRIBUTE:
while ($reader->read) {
my $name = $reader->name;
last ATTRIBUTE if 'attributes' eq $name;
next ATTRIBUTE if XML_READER_TYPE_END_ELEMENT == $reader->nodeType;
push @kids, $reader->getAttribute('value')
if 'attribute' eq $name;
}
print {$OUT} join("\t", @kids), "\n";
}
另一种方式是:
我认为大型xml文件建议使用基于语法的解析器。我只需要知道如何修改我的程序,你能帮我吗。顺便说一句,使用
openin,“>:encoding(gbk)”,$file\u data
而不是到处编码。@John很抱歉,我在XML解析方面经验有限,在SAX解析器方面一点经验都没有,也许你可以在谷歌上搜索教程。是一个开始。您必须始终在程序的开头使用strict和warnings,并在第一个使用点使用my声明所有变量。对于输出流来说,中的似乎是个奇怪的名字!谢谢,这种方式非常快,只需大约一分钟就可以将xml文件转换为txt。谢谢,我已经测试过了,它可以运行,但比choroba的答案需要更多的时间。谢谢,你们两个都很出色
#!/usr/bin/perl
use warnings;
use strict;
use XML::LibXML::Reader;
my $reader = XML::LibXML::Reader->new(location => '1.xml');
open my $OUT, '>:encoding(gbk)', '1.out';
while ($reader->read) {
attr($reader) if 'attributes' eq $reader->name
and XML_READER_TYPE_ELEMENT == $reader->nodeType;
}
sub attr {
my $reader = shift;
my @kids;
ATTRIBUTE:
while ($reader->read) {
my $name = $reader->name;
last ATTRIBUTE if 'attributes' eq $name;
next ATTRIBUTE if XML_READER_TYPE_END_ELEMENT == $reader->nodeType;
push @kids, $reader->getAttribute('value')
if 'attribute' eq $name;
}
print {$OUT} join("\t", @kids), "\n";
}
use strict;
use warnings;
use XML::Rules;
use Data::Dumper;
my @rules = (
attribute => [ attributes => sub { print "$_[1]{value}\n"; return } ],
_default => undef,
);
my $xr = XML::Rules->new( rules => \@rules );
my $data = $xr->parse($xml);