Perl:如何处理没有根节点的XML对象流



我需要用Perl解析一个大文件。(所以我将使用流解析器…)该文件包含多个XML文档(对象),但没有根节点。这会导致XML解析器在第一个Object之后中止,这是应该的。答案可能是预先/后修复一个假的根节点。

<FAKE_ROOT_TAG>Original Stream</FAKE_ROOT_TAG>

由于文件是巨大的(>1GByte),我不想复制/重写它,但宁愿使用透明的类/模块(用于XML解析器)"合并"或"连接"多个流。

stream1 : <FAKE_ROOT_TAG>                 
stream2 : Original Stream from file        >   merged stream
stream3 : </FAKE_ROOT_TAG>                / 

你能告诉我这个问题的模块或示例代码吗?

下面是一个简单的示例,通过向XML解析器传递一个伪文件句柄来实现这一点。此对象重载readline操作符(<>)以返回假根标记,其中包含文件中的行。

package FakeFile;
use strict;
use warnings;
use overload '<>' => &my_readline;
sub new {
    my $class = shift;
    my $filename  = shift;
    open my $fh, '<', $filename or die "open $filename: $!";
    return bless { fh => $fh }, $class;
}
sub my_readline {
    my $self = shift;
    return if $self->{done};
    if ( not $self->{started} ) {
        $self->{started} = 1;
        return '<fake_root_tag>';
    }
    if ( eof $self->{fh} ) {
        $self->{done} = 1;
        return '</fake_root_tag>';
    }
    return readline $self->{fh};
}

1;

如果你的解析器期望一个真正的文件句柄(例如使用sysread之类的东西),这将不起作用,但也许你会发现它鼓舞人心。

使用例子:

echo "one
two
three" > myfile
perl -MFakeFile -E 'my $f = FakeFile->new( "myfile" ); print while <$f>' 

下面是来自PerlMonks的一个小技巧:

#!/usr/bin/perl
use strict;
use warnings;
use XML::Parser;
use XML::LibXML;
my $doc_file= shift @ARGV;
my $xml=qq{
     <!DOCTYPE doc 
           [<!ENTITY real_doc SYSTEM "$doc_file">]
     >
     <doc>
         &real_doc;
     </doc>
};
{ print "XML::Parser:n";
  my $t= XML::Parser->new( Style => 'Stream')->parse( $xml);
}
{ print "XML::LibXML:n";
  my $parser = XML::LibXML->new();
  my $doc = $parser->parse_string($xml);
  print $doc->toString;
}

相关内容

  • 没有找到相关文章

最新更新