2013-05-29 4 views
5

巨大なテキストノードを含むxmlデータファイルに遭遇した後、 処理スクリプトでいくつかの方法を読んで評価しました。Perlで巨大なテキストノードを持つxmlを読むための実用的な方法

XMLファイルは アプリケーションがこの構造(例)を有する分子モデリングのための3次元座標ファイルである:

<?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ファイルは、いくつかの巨大なテキストノードを含み、60メガバイトと100メガバイトの間の大きさはに応じています内容

は、私が最初に XML::Simpleを使用してナイーブapprochを試みたが、ローダは最初にファイル解析するために永遠にかかるだろう:

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

をし、「内部エラー:巨大な入力検索」で停止するので、このアプローチISN」非常に実用的です。

次のtryは、読書のためXML::LibXMLを使用していた - しかし、ここでは、初期ローダーは、エラーメッセージが表示されてすぐに救い出すだろう「パーサーエラー:xmlSAX2Characters:巨大なテキストノード」。

stackoverflowのにこのトピックへの書き込みBefor、私は自分自身のための水溶液& Dパーサを書き、(スカラー$xmlにXX MBの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 --- 
... 
+5

http://search.cpan.org/~mirod/XML-Twig -3.44/Twig.pm - 巨大なXML文書をツリーモードで処理するためのperlモジュール。 –

+1

XML :: LibXMLでファイルをどのように開いたのですか?それは100MBのファイルのために私のために働く。 – choroba

+0

@choroba - ありがとう、もう一度チェックして、トピックを更新しました。 –

答えて

1

私はXML ::のlibxmlを使用して答えをシミュレートすることができました。これを試して、それが動作しない場合は私に知らせてください。私はposition要素に複数500K線でXMLドキュメントを作成し、私はそれを解析し、その内容を印刷することができました:

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は配列refであるため、実際に文書内にいくつのノードがあるかによってループすることができます。

+0

ありがとう!しかし、私のXML :: LibXML 2.0018 Win64はファイルをロードできません。 '$ xml = XML :: LibXML-> load_xml(location => $ fn)'は、パーサーエラー:xmlSAX2Characters:大きなテキストノードですぐに失敗します。 '$ xml = XML :: LibXML :: Reader-> new(location => $ fn)'はファイルをロードしますが、メソッドはありません: 'オブジェクトメソッドを見つけることができません。' findnodes via package "XML: :LibXML :: Reader "。 –

+0

@rubberboots使用しているlibxmlのバージョンを教えてください。あなたはPerlスクリプトの中に 'XML :: LibXML :: LIBXML_DOTTED_VERSION'を印刷することでそれを得ることができます。 – Joel

+0

nwellnhofが提案した 'huge'オプションを追加しました。今度はあなたの 'findnodes'が完璧に動作します。ありがとう。 –

2

hugeパーサのオプションでXML::LibXMLを試してみてください:

my $doc = XML::LibXML->load_xml(
    location => 'structure_80mb.xml', 
    huge  => 1, 
); 

それとも、あなたがXML::LibXML::Readerを使用する場合:

my $reader = XML::LibXML::Reader->new(
    location => 'structure_80mb.xml', 
    huge  => 1, 
); 
+0

これはそれです! Joelの 'findnodes'呼び出しと組み合わせた' huge'オプションでは、読み込みと処理はLibXMLで数秒で完了します。どうもありがとうございました! –

関連する問題