【问题标题】:Parsing an XML file line by line逐行解析 XML 文件
【发布时间】:2011-12-05 14:58:54
【问题描述】:

这就是问题所在。我正在尝试解析来自 GenBank 的 XML 信息文件。该文件包含有关多个 DNA 序列的信息。我已经为 genbacnk 的另外两种 xml 格式(TINY xml 和 INSD xml)完成了这项工作,但是纯 xml 让我头疼。这是我的程序应该如何工作的。从 GenBank 下载包含 X 个序列信息的 xml 格式文件。运行我的 perl 脚本,逐行搜索该 xml 文件并将我想要的信息打印到一个新文件中,以 fasta 格式。就是这样:>Sequence_name_and_information\n 序列\n >sequence_name.... 不断重复,直到您获得 xml 文件中的所有序列。不过,我的问题是,在纯 xml 中,序列本身位于基因或序列基因座的标识符之前。序列的基因或基因座应与“>”位于同一行。这是我打开文件并解析它的代码:

open( New_File, "+>$PWD_file/$new_file" ) or die "\n\nCouldn't create file. Check permissions on location.\n\n";

    while ( my $lines = <INSD> ) {
        foreach ($lines) {
            if (m/<INSDSeq_locus>.*<\/INSDSeq_locus>/) {
                $lines =~ s/<INSDSeq_locus>//g and $lines =~ s/<\/INSDSeq_locus>//g and $lines =~ s/[a-z, |]//g; #this last bit may cause a bug of removing the letters in the genbank accession number
                $lines =~ s/ //g;
                chomp($lines);
                print New_File ">$lines\_";
            } elsif (m/<INSDSeq_organism>.*<\/INSDSeq_organism>/) {
                $lines =~ s/<INSDSeq_organism>//g and $lines =~ s/<\/INSDSeq_organism>//g;
                $lines =~ s/(\.|\?|\-| )/_/g;
                $lines =~ s/_{2,}/_/g;
                $lines =~ s/_{1,}$//;
                $lines =~ s/^>*_{1,}//; 
                $lines =~ s/\s{2}//g;
                chomp($lines);
                print New_File "$lines\n";
            } elsif (m/<INSDSeq_sequence>.*<\/INSDSeq_sequence>/) {
                $lines =~ s/<INSDSeq_sequence>//g and $lines =~ s/<\/INSDSeq_sequence>//g;
                $lines =~ s/ //g;
                chomp($lines);
                print New_File "$lines\n";
            }
        }
    }
    close INSD;
    close New_File;
}

有两个地方可以找到基因/基因座信息。该信息位于以下两个标签之间:LOCUS_NAME 或 GENE_NAME。会有一个,或者另一个。如果一个有信息,另一个将是空的。在任何一种情况下,都需要将两者都添加到 >....... 行的末尾。

谢谢,

阿尔法A

PS--我试图通过打开 "$NA", ">" 序列来将该信息打印到“文件”,然后继续执行程序,找到基因信息,将其打印到 >行,然后读取 $NA 文件并将其打印到 > 行之后的行。我希望这很清楚。

【问题讨论】:

  • 您选择不使用 XML 解析库是否有原因?
  • 也许一个输入、当前输出和真实输出的例子会很好。
  • @DavidEG:好吧,OP 指定了 GenBank,所以 ncbi.nlm.nih.gov/genbankftp.ncbi.nih.gov/genbank
  • @Brian Roach- 两个原因,尝试学习 perl 并获得实践,这个程序是为我们一群在分子生物学实验室准备的,不是每个人都有所有的图书馆,我不能接受是时候让所有想要使用它的人都设置好所有库了。对于 DavidEG,您所说的当前输出和实际输出是什么意思?请记住,我是一名分子生物学家,为了满足我的需要而涉足 perl。这是输入文件:ncbi.nlm.nih.gov/nuccore 去那里,搜索牛肝菌,选择几个序列,去发送到(右上角)选择,文件,xml。
  • @AlphaA:有几个 XML 解析库非常常见,如果您没有安装 Perl,我会感到惊讶。有些也是纯 perl(没有 XS),因此您实际上可以将它们与您的脚本一起放在一个 tarball 中。

标签: perl parsing text


【解决方案1】:

在我看来,您应该使用XSLTXPath 来导航到您需要的数据。

正如@Brian 所建议的,使用已建立的 XML 解析技术和库更容易。

甚至还有Perl library for XSLT

【讨论】:

    【解决方案2】:

    使用 XML 解析器。我不是生物学家,我不确定您想要的最终格式,但以此为起点应该很简单。匿名子中的$_[1] 包含一个哈希引用,据我所知,我认为您希望通过解析所需标签的父标签来保存所有内容。以您希望的格式打印出 $_[1] 的元素应该很容易:

    use strict;
    use warnings;
    
    use XML::Rules;
    use Data::Dumper;
    
    my @rules = (
      _default => '',
      'INSDSeq_locus,INSDSeq_organism,INSDSeq_sequence' => 'content',
      INSDSeq  => sub { delete $_[1]{_content}; print Dumper $_[1]; return },
    );
    
    my $p = XML::Rules->new(rules => \@rules);
    $p->parsefile('sequence.gbc.xml');
    

    这只是为了轻松打印您想要的标签。或者,如果您想要一些其他标签,我真正可能会做的是(如果您只是逐个打印元素,则根本不需要 @tags 变量):

    my @tags = qw(
      INSDSeq_locus
      INSDSeq_organism
      INSDSeq_sequence
    );
    
    my @rules = (
      _default => 'content',
      # Elements are, e.g. $_[1]{INSDSeq_locus}
      INSDSeq  => sub { print "$_: $_[1]{$_}\n" for @tags; return; },
    );
    

    与:

    my $p = XML::Rules->new(rules => \@rules, stripspaces => 4);
    

    【讨论】:

    • 不需要@tags 数组和地图。您可以在字符串文字中指定多个标签名称并用逗号分隔它们:my @rules = ( 'INSDSeq_locus,INSDSeq_organism,INSDSeq_sequence' => 'content', ...
    猜你喜欢
    • 2012-10-24
    • 2014-09-14
    • 2014-09-19
    • 2018-07-21
    • 2014-10-01
    • 2019-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多