在Perl中,如何解析一个太大而无法容纳在可用内存中的XML文件?

时间:2010-07-08 23:27:37

标签: xml perl

我有一个非常大的XML文件(如果你关心,它是来自EAD的AIXM文件,但这并不重要)。为了弄清楚它是如何使用的,我想编写一个简单的脚本,遍历每个节点,记录下面发生的子节点和多少次,这样我就可以看到哪些节点包含<AptUid>以及是否大多数<Rdn>节点都有一个<GeoLat>节点,不管怎样。

我尝试使用XML::Simple将整个内容加载到hashref中,但它太大而无法放入内存中。是否有一个XML解析器,允许我一次只查看一个文件?

6 个答案:

答案 0 :(得分:8)

答案 1 :(得分:2)

您想要使用SAX解析器XML::SAX 实现start_element和end_element方法来构建节点树

答案 2 :(得分:1)

尝试XML::Parser模块。应该是你需要的。

another link

答案 3 :(得分:1)

您应该使用流式解析器,例如XML::Parser(反过来是expat以上的层)。您必须为您感兴趣的标签注册处理程序,并自己进行簿记。与其他流式模型(如SAX)一样,您无法立即获得文件的完整视图(除了您在代码中明确使用的子集)。

答案 4 :(得分:1)

这是使用XML :: Parser的解决方案。欢迎评论。

use XML::Parser;

%elemMap = ();

@context = ();

sub on_start {
    my ($p, $elemName, @alist) = @_;
    my $parent = @context[-1];
    if ($parent) {
        $elemMap{$parent}{$elemName}++;
    }        
    push(@context, $elemName);
}

sub on_end {
    pop(@context);
}

$p = new XML::Parser(Handlers => {Start => \&on_start, End => \&on_end});
$p->parse(STDIN);

while (my ($elem, $childElems) = each(%elemMap)) {
    while (my ($childElem, $count) = each(%{$childElems})) {
        print "$elem > $childElem: $count\n";
    }
}

答案 5 :(得分:0)

当您第一次尝试找出未知XML文件的结构时,请将其打开更少或更多,然后开始对其进行分页。不要使用试图将整个文件加载到内存中的编辑器,除非您喜欢等待​​很多机器。

当你不知道数据是如何构造时构建一个解析器会非常令人沮丧,所以不要先进入编码,跳到探索直到你知道足够开始编码为止。