2013-05-29 9 views
5

Sau khi gặp các tệp dữ liệu xml chứa các nút văn bản lớn, Tôi đã tìm một số cách để đọc và đánh giá chúng trong dữ liệu của tôi xử lý tập lệnh.Cách thực hành đọc xml với các nút văn bản lớn trong Perl

Các tập tin xml là các tập tin phối hợp 3D cho mô hình phân tử ứng dụng một có cấu trúc này (ví dụ):

<?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> 

Mỗi file xml chứa một số nút văn bản rất lớn và có kích thước giữa 60MB và 100MB tùy thuộc vào Nội dung.

tôi đã cố gắng approch ngây thơ sử dụng XML::Simple đầu tiên nhưng bộ nạp sẽ mất mãi mãi để bước đầu phân tích các file:

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

và chỉ dừng lại ở "lỗi nội bộ: tra cứu đầu vào lớn", do đó phương pháp này isn' t rất thực tế.

Lần thử tiếp theo là sử dụng XML::LibXML để đọc - nhưng tại đây, trình nạp ban đầu sẽ được gửi ngay lập tức với thông báo lỗi "lỗi phân tích cú pháp: xmlSAX2Characters: nút văn bản lớn".

Befor viết về chủ đề này trên stackoverflow, tôi đã viết aq & d phân tích cú pháp cho bản thân mình và gửi các tập tin thông qua nó (sau khi slurping xx MB file xml vào vô hướng $xml):

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

mà trả về dữ liệu của mỗi dòng dưới dạng một mảng, hoàn thành trong vài giây và trông giống như sau:

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; 
} 

Điều này làm việc tốt cho đến nay nhưng không được coi là 'sẵn sàng sản xuất', tất nhiên.

Hỏi: Làm cách nào để đọc tệp bằng mô-đun Perl? Tôi sẽ chọn mô-đun nào?

Cảm ơn trước

RBO


Phụ Lục: sau khi đọc bình luận của choroba, tôi nhìn sâu hơn vào XML :: LibXML. Việc mở tập tin my $reader = XML::LibXML::Reader->new(location =>'structure_80mb.xml'); hoạt động, trái với những gì tôi nghĩ trước đây. Lỗi xảy ra nếu tôi cố truy cập vào nút văn bản bên dưới thẻ:

... 
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 - mô-đun perl để xử lý các tài liệu XML lớn trong chế độ cây. –

+1

Bạn đã mở tệp bằng XML :: LibXML như thế nào? Nó làm việc cho tôi cho các tập tin 100MB. – choroba

+0

@choroba - cảm ơn, tôi đã kiểm tra lại - và cập nhật chủ đề. –

Trả lời

1

Tôi có thể mô phỏng câu trả lời bằng XML :: LibXML. Hãy thử điều này và cho tôi biết nếu nó không hoạt động. Tôi tạo ra một doc XML với hơn 500k dòng trong các yếu tố position, và tôi đã có thể phân tích nó và in nội dung của nó:

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"; 

Tôi đang sử dụng findnodes sử dụng một biểu thức XPath để kéo ra tất cả các nút mà tôi muốn. $nodes chỉ là một tham chiếu mảng, vì vậy bạn có thể lặp lại nó tùy thuộc vào số lượng nút bạn thực sự có trong tài liệu của mình.

+0

Cảm ơn! Nhưng XML của tôi :: LibXML 2.0018 Win64 không thể tải tệp. '$ xml = XML :: LibXML-> load_xml (vị trí => $ fn)' không thành công ngay lập tức w/'lỗi trình phân tích cú pháp: xmlSAX2Characters: nút văn bản lớn'. Trong khi '$ xml = XML :: LibXML :: Reader-> new (location => $ fn)' tải tệp, nhưng không có phương thức: 'Không thể định vị phương thức đối tượng" tìm kiếm "qua gói" XML: : LibXML :: Reader "'. –

+0

@rubberboots Bạn có thể cung cấp phiên bản libxml nào bạn đang sử dụng không? Bạn có thể lấy nó bằng cách in 'XML :: LibXML :: LIBXML_DOTTED_VERSION' bên trong kịch bản Perl của bạn. – Joel

+0

Tôi đã thêm tùy chọn 'lớn' theo đề xuất của nwellnhof. Bây giờ, 'findnodes' của bạn hoạt động hoàn hảo. Cảm ơn. –

2

Hãy thử XML::LibXML với các tùy chọn huge phân tích cú pháp:

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

Hoặc, nếu bạn muốn sử dụng XML::LibXML::Reader:

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

Đây là nó! Với tùy chọn 'lớn', kết hợp với cuộc gọi' findnodes' của Joel, việc đọc và xử lý được thực hiện trong vài giây thông qua LibXML. Cảm ơn nhiều! –