5

巨大なテキスト ノードを含む xml データ ファイルに遭遇した後、データ処理スクリプトでそれらを読み取って評価する方法をいくつか探しました。

xml ファイルは、分子モデリング アプリケーション用の 3D 座標ファイルであり、次の構造を持っています (例):

<?xml version="1.0" encoding="UTF-8"?>
<hoomd_xml version="1.4">
   <configuration>
      <position>
        -0.101000   0.011000  -40.000000
        -0.077000   0.008000  -40.469000
        -0.008000   0.001000  -40.934000
        -0.301000   0.033000  -41.157000
         0.213000  -0.023000  -41.348000
         ...
         ... 300,000 to 500,000 lines may follow  >>
         ...
        -0.140000   0.015000  -42.556000
      </position>

      <next_huge_section_of_the_same_pattern>
        ...
        ...
        ...
      </next_huge_section_of_the_same_pattern>

   </configuration>
</hoomd_xml>

各 xml ファイルには、いくつかの巨大なテキスト ノードが含まれており、内容に応じて 60MB から 100MB のサイズになります。

最初にXML::Simpleを使用して単純なアプローチを試みましたが、ローダーが最初にファイルを解析するのに永遠に時間がかかります。

...
my $data = $xml->XMLin('structure_80mb.xml');
...

「 internal error: huge input lookup 」で停止するため、このアプローチはあまり実用的ではありません。

次の試みは、読み取りにXML::LibXMLを使用することでしたが、ここでは、初期ローダーがすぐに「parser error : xmlSAX2Characters: huge text node」というエラー メッセージを出してしまいます。

stackoverflowでこのトピックについて書く前に、私は自分用に q&d パーサーを作成し、それを介してファイルを送信しました (xx MB xml ファイルを scalar に丸呑みした後$xml):

...
# read the <position> data from in-memory xml file
my @Coord = xml_parser_hack('position', $xml);
...

各行のデータを配列として返し、数秒以内に完了し、次のようになります。

sub xml_parser_hack {
 my ($tagname, $xml) = @_;
 return () unless $xml =~ /^</;

 my @Data = ();
 my ($p0, $p1) = (undef,undef);
 $p0 = $+[0] if $xml =~ /^<$tagname[^>]*>[^\r\n]*[r\n]+/msg; # start tag
 $p1 = $-[0] if $xml =~ /^<\/$tagname[^>]*>/msg;             # end tag
 return () unless defined $p0 && defined $p1;
 my @Lines = split /[\r\n]+/, substr $xml, $p0, $p1-$p0;
 for my $line (@Lines) {
    push @Data, [ split /\s+/, $line ];
 }
 return @Data;
}

これは今のところ問題なく動作しますが、もちろん「本番環境の準備ができている」とは見なされません。

Q: Perl モジュールを使用してファイルを読み取るにはどうすればよいですか? どのモジュールを選択しますか?

前もって感謝します

rbo


補遺: choroba のコメントを読んだ後、XML::LibXML を詳しく調べました。my $reader = XML::LibXML::Reader->new(location =>'structure_80mb.xml'); 以前に思っていたのとは逆に、ファイルを開くことができます。タグの下のテキスト ノードにアクセスしようとすると、エラーが発生します。

...
while ($reader->read) {
   # bails out in the loop iteration after accessing the <position> tag,
   # if the position's text node is accessed
   #   --  xmlSAX2Characters: huge text node ---
...
4

2 に答える 2

1

XML::LibXML を使用して、回答をシミュレートすることができました。これを試して、うまくいかない場合はお知らせください。要素に50 万行を超える XML ドキュメントを作成し、positionそれを解析して内容を出力することができました。

use strict;
use warnings;
use XML::LibXML;

my $xml = XML::LibXML->load_xml(location => '/perl/test.xml');
my $nodes = $xml->findnodes('/hoomd_xml/configuration/position');
print $nodes->[0]->textContent . "\n";
print scalar(@{$nodes}) . "\n";

XPath式を使用findnodesして、必要なすべてのノードを引き出しています。 $nodesは単なる配列参照であるため、ドキュメント内に実際にあるノードの数に応じてループすることができます。

于 2013-05-29T13:13:27.280 に答える