File Coverage

GO/Parsers/ncbi_taxonomy_parser.pm
Criterion Covered Total %
statement 99 106 93.4
branch 22 30 73.3
condition 2 3 66.6
subroutine 11 11 100.0
pod 0 3 0.0
total 134 153 87.5


line stmt bran cond sub pod time code
1             # $Id: ncbi_taxonomy_parser.pm,v 1.10 2008/02/05 00:34:15 cmungall Exp $
2             #
3             #
4             # see also - http://www.geneontology.org
5             # - http://www.godatabase.org/dev
6             #
7             # You may distribute this module under the same terms as perl itself
8              
9             package GO::Parsers::ncbi_taxonomy_parser;
10              
11             =head1 NAME
12              
13             GO::Parsers::ncbi_taxonomy_parser
14              
15             =head1 SYNOPSIS
16              
17             do not use this class directly; use GO::Parser
18              
19             =cut
20              
21             =head1 DESCRIPTION
22              
23             See L
24              
25              
26             =head1 PARSER ARCHITECTURE
27              
28             This generates Stag event streams from one of the various GO flat file
29             formats (ontology, defs, xref, associations). See GO::Parser for details
30              
31             Examples of these files can be found at http://www.geneontology.org
32              
33             A description of the event streams generated follows; Stag or an XML
34             handler can be used to catch these events
35              
36             =cut
37              
38 1     1   5 use Exporter;
  1         1  
  1         56  
39 1     1   7 use base qw(GO::Parsers::base_parser);
  1         1  
  1         490  
40 1     1   493 use GO::Parsers::ParserEventNames; # declare XML constants
  1         3  
  1         231  
41              
42 1     1   4 use Carp;
  1         2  
  1         49  
43 1     1   4 use FileHandle;
  1         1  
  1         8  
44 1     1   526 use strict qw(subs vars refs);
  1         3  
  1         2345  
45              
46             my %synonymtypes =
47             (
48             'genbank synonym'=>['related'],
49             'synonym'=>['related'],
50             'in-part'=>['related'],
51             'blast name'=>['related'],
52             'misnomer'=>['related'],
53             'misspelling'=>['related'],
54             'scientific name'=>['exact'],
55             'equivalent name'=>['exact'],
56             'common name'=>['exact'],
57             'genbank common name'=>['exact'],
58             'acronym'=>['broad'],
59             'genbank acronym'=>['broad'],
60             'teleomorph'=>['related'],
61             'anamorph'=>['related'],
62             'genbank anamorph'=>['related'],
63             );
64              
65             sub syn {
66 293     293 0 403 my $name = shift;
67 293         623 $name =~ s/\s/_/g;
68 293         420 $name =~ s/\-/_/g;
69 293         1793 $name;
70             }
71              
72             sub parse_fh {
73 1     1 0 224 my ($self, $fh) = @_;
74 1         7 my $file = $self->file;
75 1         9 $self->{name_h} = {};
76              
77 1         13 $self->start_event(OBO);
78 15         37 $self->event(header=>
79             [
80             ['default-namespace'=>'ncbi_taxonomy'],
81             ['ontology'=>'ncbitaxon'],
82             [remark=>'autogenerated via GO::Parsers::ncbi_taxonomy_parser'],
83 1         23 (map {[synonymtypedef=>[[id=>syn($_)],[name=>$_],[scope=>$synonymtypes{$_}->[0]]]]} keys %synonymtypes),
84             ]);
85              
86 1         69 $self->event(typedef=>
87             [
88             [id=>'has_rank'],
89             [name=>"has_rank"],
90             [def=>[[defstr=>"A metadata relation between a class and its taxonomic rank (eg species, family)"]]],
91             [is_metadata_tag=>1],
92             [comment=>"This is an abstract class for use with the NCBI taxonomy to name the depth of the node within the tree. The link between the node term and the rank is only visible if you are using an obo 1.3 aware browser/editor; otherwise this can be ignored"]
93             ]);
94              
95 1         46 $self->event(term=>
96             [
97             [id=>_fix_id("taxonomic_rank")],
98             [name=>"taxonomic_rank"],
99             [def=>[[defstr=>"A level of depth within a species taxonomic tree"]]],
100             [comment=>"This is an abstract class for use with the NCBI taxonomy to name the depth of the node within the tree. The link between the node term and the rank is only visible if you are using an obo 1.3 aware browser/editor; otherwise this can be ignored"]
101             ]);
102              
103 1         52 my $lnum = 0;
104 1         3 my %h = ();
105 1         2 my $text;
106 1         38 while (my $line = <$fh>) {
107 996         1320 chomp $line;
108 996 100       1869 if ($line eq '//') {
109 117         384 $self->emit_term(\%h,$text);
110 117         7952 %h = ();
111 117         957 $text = '';
112             }
113             else {
114 879 50       3877 if ($line =~ /^([\w\s\-]+)\s+:\s*(.*)/) {
115 879         2272 my ($k,$v) = ($1,$2);
116 879         1377 $k = lc($k); # lowercase
117 879         2901 $k =~ s/\s+$//; # removing trailing ws
118 879         1153 push(@{$h{$k}},$v);
  879         2537  
119             }
120             else {
121 0         0 $self->parse_err("Line: $line");
122             }
123 879         4026 $text .= "$line\n";
124             }
125             }
126 1         20 $self->pop_stack_to_depth(0); # end event obo
127             }
128              
129             sub _rank_id {
130 126     126   258 my $rank = shift;
131 126         279 $rank =~ s/\s+/_/g;
132 126         237 _fix_id($rank);
133             }
134              
135             sub _fix_id {
136 360     360   1441 return "NCBITaxon:$_[0]";
137             }
138              
139             sub emit_term {
140 117     117 0 242 my ($self, $h, $text) = @_;
141 117         144 my $id = pop @{$h->{id}};
  117         265  
142 117 50       289 if (!$id) {
143 0         0 $self->parse_err("No id! in:\n$text");
144 0         0 return;
145             }
146 117         212 $id = _fix_id($id);
147 117         465 $self->start_event(TERM);
148 117         3701 $self->event(ID,$id);
149 117         9699 my $name = pop @{$h->{'scientific name'}};
  117         281  
150 117 100       177 my ($gname) = @{$h->{'genbank common name'} || []};
  117         742  
151 117 50       296 if (!$name) {
152 0         0 $name = $gname;
153 0 0       0 pop @{$h->{'genbank common name'}} if $gname;
  0         0  
154             }
155 117 50       438 if ($self->{name_h}->{$name}) {
156 0         0 $name .= " [$id]"; # force unique
157             }
158 117         353 $self->{name_h}->{$name} = $id;
159 117         350 $self->event(NAME, $name);
160 117         8829 foreach my $st (keys %synonymtypes) {
161 1755         50674 my $syns = $h->{$st};
162 1755 100       3302 next unless $syns;
163 253         516 my $scope = $synonymtypes{$st}->[0];
164 253         484 foreach my $s (@$syns) {
165 278         70111 my @xrefs = ();
166 278 100 66     1667 if ($s =~ /\"(.+)\"\s*(.+)/ ||
167             $s =~ /\'(.+)\'\s*(.+)/) {
168 56         159 my $xref = $2;
169 56         121 $s = $1;
170 56         312 $xref =~ s/\s+/_/g;
171 56         109 $xref =~ tr/\(\)//d;
172 56         112 $xref =~ tr/\[\]//d;
173 56         86 $xref =~ s@,@\\,@g;
174 56         254 push(@xrefs, [dbxref=>[[acc=>$xref],[dbname=>"NCBITaxonRef"]]]);
175             }
176 278         990 $self->event(SYNONYM,[
177             ['@'=>[['scope',$scope],
178             [SYNONYM_TYPE,syn($st)]]],
179             [SYNONYM_TEXT,$s],
180             @xrefs]);
181             }
182             }
183 117         295 my $rank = pop @{$h->{rank}};
  117         286  
184 117 100       331 if ($rank eq 'no rank') {
185 1         4 $rank = undef;
186             }
187 117 100       296 if ($rank) {
188 116 100       430 if (!$self->{__rank}->{$rank}) {
189 5         16 $self->{__rank}->{$rank} = 1;
190 5         15 $self->event(TERM,[[ID,_rank_id($rank)],
191             [NAME,$rank],
192             [IS_A,_rank_id('taxonomic_rank')],
193             ]);
194             }
195              
196             #this is the correct way to handle this - as annotation properties
197 116 50       865 $self->event(PROPERTY_VALUE,[[TYPE,'has_rank'],
198             [TO,_rank_id($rank)]])
199             if $rank;
200            
201             # do it this way for now until oboedit is fixed:
202             # $self->event(RELATIONSHIP,[[TYPE,'has_rank'],
203             # [TO,_rank_id($rank)]])
204             }
205              
206 117         25190 my $gc = pop @{$h->{'gc id'}};
  117         310  
207 117 50       625 $self->event(XREF, "GC_ID:$gc") if $gc;
208 117         8505 my $parent_id = pop @{$h->{'parent id'}};
  117         288  
209 117 100       299 if ($parent_id) {
210 116         236 $parent_id = _fix_id($parent_id);
211 116         385 $self->event(IS_A,$parent_id);
212             }
213 117         8414 $self->end_event(TERM);
214             }
215              
216             1;