File Coverage

Bio/SeqIO/tigr.pm
Criterion Covered Total %
statement 30 667 4.5
branch 0 262 0.0
condition 0 36 0.0
subroutine 10 44 22.7
pod 2 2 100.0
total 42 1011 4.1


line stmt bran cond sub pod time code
1             # BioPerl module for Bio::SeqIO::tigr
2             #
3             # Please direct questions and support issues to
4             #
5             # Cared for by Josh Lauricha (laurichj@bioinfo.ucr.edu)
6             #
7             # Copyright Josh Lauricha
8             #
9             # You may distribute this module under the same terms as perl itself
10              
11             # POD documentation - main docs before the code
12              
13             =head1 NAME
14              
15             Bio::SeqIO::tigr - TIGR XML sequence input/output stream
16              
17             =head1 SYNOPSIS
18              
19             Do not use this module directly. Use it via the Bio::SeqIO class.
20              
21             =head1 DESCRIPTION
22              
23             This object can transform Bio::Seq objects to and from efa flat
24             file databases.
25              
26             =head1 FEEDBACK
27              
28             =head2 Mailing Lists
29              
30             User feedback is an integral part of the evolution of this and other
31             Bioperl modules. Send your comments and suggestions preferably to one
32             of the Bioperl mailing lists. Your participation is much appreciated.
33              
34             bioperl-l@bioperl.org - General discussion
35             http://bioperl.org/wiki/Mailing_lists - About the mailing lists
36              
37             =head2 Support
38              
39             Please direct usage questions or support issues to the mailing list:
40              
41             I
42              
43             rather than to the module maintainer directly. Many experienced and
44             reponsive experts will be able look at the problem and quickly
45             address it. Please include a thorough description of the problem
46             with code and data examples if at all possible.
47              
48             =head2 Reporting Bugs
49              
50             Report bugs to the Bioperl bug tracking system to help us keep track
51             the bugs and their resolution.
52             Bug reports can be submitted via the web:
53              
54             https://github.com/bioperl/bioperl-live/issues
55              
56             =head1 AUTHORS - Josh Lauricha
57              
58             Email: laurichj@bioinfo.ucr.edu
59              
60              
61             =head1 APPENDIX
62              
63             The rest of the documentation details each of the object
64             methods. Internal methods are usually preceded with a _
65              
66             =cut
67              
68             # TODO:
69             # - Clean up code
70             # - Find and fix bugs ;)
71              
72             # Let the code begin...
73             package Bio::SeqIO::tigr;
74 1     1   473 use strict;
  1         1  
  1         24  
75              
76 1     1   216 use Bio::Seq::RichSeq;
  1         3  
  1         31  
77 1     1   264 use Bio::Species;
  1         3  
  1         22  
78 1     1   207 use Bio::Annotation::Comment;
  1         2  
  1         22  
79 1     1   286 use Bio::SeqFeature::Generic;
  1         2  
  1         23  
80 1     1   5 use Bio::Seq::SeqFactory;
  1         1  
  1         16  
81 1     1   4 use Bio::Seq::RichSeq;
  1         2  
  1         14  
82 1     1   4 use Data::Dumper;
  1         1  
  1         41  
83 1     1   5 use Error qw/:try/;
  1         1  
  1         6  
84              
85 1     1   131 use base qw(Bio::SeqIO);
  1         2  
  1         307  
86              
87             sub _initialize
88             {
89 0     0     my($self, @args) = @_;
90              
91 0           $self->SUPER::_initialize(@args);
92 0           $self->sequence_factory(Bio::Seq::SeqFactory->new(
93             -type => 'Bio::Seq::RichSeq')
94             );
95              
96             # Parse the document
97 0           $self->_process();
98             }
99              
100             =head2 next_seq
101              
102             Title : next_seq
103             Usage : $seq = $stream->next_seq()
104             Function: returns the next sequence in the stream
105             Returns : Bio::Seq object
106             Args : NONE
107              
108             =cut
109              
110             sub next_seq()
111             {
112 0     0 1   my ($self) = @_;
113            
114             # Check for any more sequences
115 0 0 0       return if !defined($self->{_sequences}) or scalar(@{$self->{_sequences}}) < 1;
  0            
116              
117             # get the next sequence
118 0           my $seq = shift(@{ $self->{_sequences} } );
  0            
119              
120             # Get the 5' and 3' ends
121 0           my ($source) = grep { $_->primary_tag() eq 'source' } $seq->get_SeqFeatures();
  0            
122 0           my ($end5) = $source->get_tag_values('end5');
123 0           my ($end3) = $source->get_tag_values('end3');
124              
125             # Sort the 5' and 3':
126 0 0         my ($start, $end) = ( $end5 < $end3 ? ( $end5, $end3 ) : ( $end3, $end5 ) );
127              
128             # make the start a perl index
129 0           $start -= 1;
130              
131             # Figure out the length
132 0           my $length = $end - $start;
133              
134             # check to make sure $start >= 0 and $end <= length(assembly_seq)
135 0 0         if($start < 0) {
    0          
    0          
136 0           throw Bio::Root::OutOfRange("the sequence start is $start < 0");
137             } elsif($end > length($self->{_assembly}->{seq})) {
138 0           throw Bio::Root::OutOfRange("the sequence end is $end < " . length($self->{_assembly}->{seq}));
139             } elsif($start >= $end) {
140 0           throw Bio::Root::OutOfRange("the sequence start is after end $start >= $end");
141             }
142              
143             # Get and set the real sequence
144 0           $seq->seq(substr($self->{_assembly}->{seq}, $start, $length));
145              
146 0 0         if( $end5 > $end3 ) {
147             # Reverse complement the sequence
148 0           $seq->seq( $seq->primary_seq()->revcom()->seq() );
149             }
150              
151             # add the translation to each CDS
152 0           foreach my $feat ($seq->get_SeqFeatures()) {
153 0 0         next if $feat->primary_tag() ne "CDS";
154              
155             # Check for an invalid protein
156             try {
157             # Get the subsq
158 0     0     my $cds = Bio::PrimarySeq->new(
159             -strand => 1,
160             -id => $seq->accession_number(),
161             -seq => $seq->subseq($feat->location())
162             );
163              
164             # Translate it
165 0           my $trans = $cds->translate(undef, undef, undef, undef, 1, 1)->seq();
166              
167             # Add the tag
168 0           $feat->add_tag_value(translation => $trans);
169             } catch Bio::Root::Exception with {
170 0 0   0     print STDERR 'TIGR strikes again, the CDS is not a valid protein: ', $seq->accession_number(), "\n"
171             if $self->verbose() > 0;
172 0           };
173             }
174              
175             # Set the display id to the accession number if there
176             # is no display id
177 0 0         $seq->display_id( $seq->accession_number() ) unless $seq->display_id();
178            
179 0           return $seq;
180             }
181              
182             sub _process
183             {
184 0     0     my($self) = @_;
185 0           my $line;
186 0           my $tu = undef;
187              
188 0           $line = $self->_readline();
189 0           do {
190 0 0         if($line =~ /<\?xml\s+version\s+=\s+"\d+\.\d+"\?>/o) {
    0          
    0          
    0          
    0          
191             # do nothing
192             } elsif ($line =~ //o) {
193 0 0         $self->throw("DOCTYPE of $1, not TIGR!")
194             if $1 ne "TIGR" ;
195             } elsif ($line =~ //o) {
196 0           $self->_pushback($line);
197 0           $self->_process_tigr();
198             } elsif ($line =~ //o) {
199 0           $self->_pushback($line);
200 0           $self->_process_assembly();
201             } elsif ($line =~ /<\/TIGR>/o) {
202 0           $self->{'eof'} = 1;
203 0           return;
204             } else {
205 0           $self->throw("Unknown or Invalid process directive:",
206             join('', ($line =~ /^\s*(<[^>]+>)/o)));
207             }
208 0           $line = $self->_readline();
209             } while( defined( $line ) );
210             }
211              
212             sub _process_tigr
213             {
214 0     0     my($self) = @_;
215 0           my $line;
216              
217 0           $line = $self->_readline();
218 0 0         if($line !~ //o) {
219 0           $self->throw("Bio::SeqIO::tigr::_process_tigr called but no ",
220             " found in stream");
221             }
222              
223 0           $line = $self->_readline();
224 0 0         if($line =~ //o) {
    0          
225 0           $self->_pushback($line);
226 0           $self->_process_pseudochromosome();
227             } elsif ($line =~ //o) {
228 0           $self->_pushback($line);
229 0           $self->_process_assembly();
230             }
231             }
232              
233             sub _process_pseudochromosome
234             {
235 0     0     my($self) = @_;
236 0           my $line;
237              
238 0           $line = $self->_readline();
239 0 0         return if $line !~ //o;
240              
241 0           $line = $self->_readline();
242              
243 0 0         if($line =~ //o) {
244 0           $self->_pushback($line);
245 0           $self->_process_scaffold();
246 0           $line = $self->_readline();
247             } else {
248 0           $self->warn( "No Scaffold found in this " .
249             "is a violation of the TIGR dtd, but we ignore " .
250             "it so we are ignoring the error\n"
251             );
252             }
253              
254 0 0         if($line =~ //o) {
255 0           $self->_pushback($line);
256 0           $self->_process_assembly();
257 0           $line = $self->_readline();
258             } else {
259 0           $self->throw("Missing required ASSEMBLY in ");
260             }
261              
262 0 0         if($line =~ /<\/PSEUDOCHROMOSOME>/) {
263 0           return;
264             }
265              
266 0           $self->throw("Reached end of _process_pseudochromosome");
267             }
268              
269             sub _process_assembly
270             {
271 0     0     my($self) = @_;
272 0           my $line;
273              
274 0           $line = $self->_readline();
275 0 0         if($line !~ /]*)>/o) {
276 0           $self->throw("Bio::SeqIO::tigr::_process_assembly called ",
277             "but no found in stream");
278             }
279              
280 0           my %attribs = ($1 =~ /(\w+)\s*=\s+"(.*?)"/og);
281 0           $self->{_assembly}->{date} = $attribs{CURRENT_DATE};
282 0           $self->{_assembly}->{db} = $attribs{DATABASE};
283 0           $self->{_assembly}->{chromosome} = $attribs{CHROMOSOME};
284              
285 0           $line = $self->_readline();
286 0           my($attr, $val);
287 0 0         if(($attr, $val) = ($line =~ /]*)>([^<]*)<\/ASMBL_ID>/o)) {
288 0           %attribs = ($attr =~ /(\w+)\s*=\s+"(.*?)"/og);
289 0           $self->{_assembly}->{clone_name} = $attribs{CLONE_NAME};
290 0           $self->{_assembly}->{clone} = $val;
291 0           $line = $self->_readtag();
292             } else {
293 0           $self->throw("Required missing");
294             }
295              
296 0 0         if($line =~ //o) {
297 0           $self->_pushback($line);
298 0           my $cs = $self->_process_coordset();
299              
300 0           $self->{_assembly}->{end5} = $cs->{end5};
301 0           $self->{_assembly}->{end3} = $cs->{end3};
302              
303 0           $line = $self->_readline();
304             } else {
305 0           $self->throw("Required missing");
306             }
307              
308 0 0         if($line =~ /
/o) {
309 0           $self->_pushback($line);
310 0           $self->_process_header();
311 0           $line = $self->_readline();
312             } else {
313 0           $self->throw("Required
missing");
314             }
315              
316 0 0         if($line =~ //o) {
317 0           $self->_pushback($line);
318 0           $self->_process_tiling_path();
319 0           $line = $self->_readline();
320             }
321              
322 0 0         if($line =~ //o) {
323 0           $self->_pushback($line);
324 0           $self->_process_gene_list();
325 0           $line = $self->_readline();
326             } else {
327 0           $self->throw("Required missing");
328             }
329              
330 0 0         if($line =~ //o) {
331 0           $self->_pushback($line);
332 0           $self->_process_misc_info();
333 0           $line = $self->_readline();
334             }
335              
336 0 0         if($line =~ //o) {
337 0           $self->_pushback($line);
338 0           $self->_process_repeat_list();
339 0           $line = $self->_readline();
340             }
341              
342 0 0         if($line =~ //o) {
343 0           $self->_pushback($line);
344 0           $self->_process_assembly_seq();
345 0           $line = $self->_readline();
346             } else {
347 0           $self->throw("Required missing");
348             }
349              
350 0 0         if($line =~ /<\/ASSEMBLY>/o) {
351 0           return;
352             }
353 0           $self->throw("Reached the end of ");
354             }
355              
356             sub _process_assembly_seq()
357             {
358 0     0     my ($self) = @_;
359 0           my $line;
360            
361 0           $line = $self->_readline();
362 0 0         if($line !~ //o) {
363 0           $self->throw("Bio::SeqIO::tigr::_process_assembly_seq called ".
364             "with no in the stream");
365             }
366              
367             # Protect against lots of smaller lines
368 0           my @chunks;
369              
370 0           do {
371 0           $line = $self->_readline();
372 0 0         last unless $line;
373              
374 0           my $seq;
375 0 0         if (($seq) = ($line =~ /^\s*(\w+)\s*$/o)) {
    0          
376 0           push(@chunks, $seq);
377             } elsif( ($seq) = ( $line =~ /^\s*(\w+)<\/ASSEMBLY_SEQUENCE>\s*$/o) ) {
378 0           push(@chunks, $seq);
379 0           $self->{_assembly}->{seq} = join('', @chunks);
380 0           return;
381             }
382             } while( $line );
383              
384 0           $self->throw("Reached end of _proces_assembly");
385             }
386              
387             sub _process_coordset($)
388             {
389 0     0     my ($self) = @_;
390 0           my $line;
391             my $h;
392              
393 0           $line = $self->_readline();
394 0 0         if($line =~ //o) {
395 0           $self->_pushback($line);
396 0           $line = $self->_readtag();
397 0           ($h->{end5}, $h->{end3}) = ($line =~ /\s*\s*(\d+)\s*<\/END5>\s*\s*(\d+)\s*<\/END3>/os);
398 0 0 0       if(!defined($h->{end5}) or !defined($h->{end3})) {
399 0           $self->throw("Invalid : $line");
400             }
401 0           return $h;
402             } else {
403 0           $self->throw("Bio::SeqIO::tigr::_process_coordset() called ",
404             "but no found in stream");
405             }
406             }
407              
408             sub _process_header
409             {
410 0     0     my ($self) = @_;
411 0           my $line = $self->_readline();
412              
413 0 0         if($line !~ /
/o) {
414 0           $self->throw("Bio::SeqIO::tigr::_process_header called ",
415             "but no
found in stream");
416             }
417              
418 0           $line = $self->_readtag();
419 0 0         if($line =~ /([^>]+)<\/CLONE_NAME>/o) {
420 0           $self->{_assembly}->{clone_name} = $1;
421 0           $line = $self->_readtag();
422             } else {
423 0           $self->throw("Required missing");
424             }
425              
426 0 0         if($line =~ //o) {
427             # Ignored for now
428 0           $line = $self->_readtag();
429             } else {
430 0           $self->throw("Reqired missing");
431             }
432              
433 0 0         if($line =~ /([^<]*)<\/GB_ACCESSION>/o) {
434 0           $self->{_assembly}->{gb} = $1;
435 0           $line = $self->_readtag();
436             } else {
437 0           $self->throw("Required missing");
438             }
439              
440 0 0         if($line =~ /\s*(.+)\s*<\/ORGANISM>/o) {
441 0           my( $genus, $species, @ss ) = split(/\s+/o, $1);
442 0           $self->{_assembly}->{species} = Bio::Species->new();
443 0           $self->{_assembly}->{species}->genus($genus);
444 0           $self->{_assembly}->{species}->species($species);
445 0 0         $self->{_assembly}->{species}->sub_species(join(' ', @ss)) if scalar(@ss) > 0;
446              
447 0           $line = $self->_readtag();
448             } else {
449 0           $self->throw("Required missing");
450             }
451              
452 0 0         if($line =~ /([^<]*)<\/LINEAGE>/o) {
453             $self->{_assembly}->{species}->classification(
454 0           $self->{_assembly}->{species}->species(),
455             reverse(split(/\s*;\s*/o, $1))
456             );
457 0           $line = $self->_readtag();
458             } else {
459 0           $self->throw("Required missing");
460             }
461              
462 0 0         if($line =~ /([^<]*)<\/SEQ_GROUP>/o) {
463             # ingnored
464 0           $line = $self->_readtag();
465             } else {
466 0           $self->throw("Required missing");
467             }
468              
469 0           while($line =~ /[^<]*<\/KEYWORDS>/o) {
470 0           push(@{$self->{_assembly}->{keywords}}, $1);
  0            
471 0           $line = $self->_readtag();
472             }
473              
474 0           while($line =~ /([^<]+)<\/GB_DESCRIPTION>/o) {
475 0           push(@{$self->{_assembly}->{gb_desc}},$1);
  0            
476 0           $line = $self->_readtag();
477             }
478              
479 0           while($line =~ /([^<]+)<\/GB_COMMENT>/o) {
480 0           push(@{$self->{_assembly}->{gb_comment}}, $1);
  0            
481 0           $line = $self->_readtag();
482             }
483              
484 0 0         if(my %h = ($line =~ //o)) {
485             #$header->{'AUTHOR_LIST'}=$h{'CONTACT'};
486             # Ignored
487 0           while($line !~ /<\/AUTHOR_LIST>/o) {
488 0           $self->_readtag();
489             }
490 0           $line = $self->_readline();
491             } else {
492 0           $self->throw("Required missing");
493             }
494              
495 0 0         if($line =~ /<\/HEADER>/o) {
496 0           return;
497             }
498              
499 0           $self->throw("Reached end of header\n");
500             }
501              
502             sub _process_gene_list
503             {
504 0     0     my($self) = @_;
505 0           my $line;
506              
507 0           $line = $self->_readline();
508 0 0         if($line !~ //o) {
509 0           $self->throw("Bio::SeqIO::tigr::_process_gene_list called ",
510             "but no in the stream");
511             }
512              
513 0           $line = $self->_readline();
514 0 0         if($line =~ //o) {
515 0           $self->_pushback($line);
516 0           $self->_process_protein_coding();
517 0           $line = $self->_readline();
518             } else {
519 0           $self->throw("Required missing");
520             }
521              
522 0 0         if($line =~ //o) {
523 0           $self->_pushback($line);
524 0           $self->_process_rna_genes();
525 0           $line = $self->_readline();
526             } else {
527 0           $self->throw("Required missing");
528             }
529              
530 0 0         if($line =~ /<\/GENE_LIST>/o) {
531 0           return;
532             }
533              
534 0           $self->throw("Reached end of _process_gene_list");
535             }
536              
537             sub _process_protein_coding
538             {
539 0     0     my ($self) = @_;
540 0           my $line = $self->_readline();
541              
542 0 0         if($line !~ //o) {
543 0           $self->throw("Bio::SeqIO::tigr::_process_protein_coding called"
544             . "but no in the stream");
545             }
546              
547 0           $line = $self->_readline();
548 0   0       while($line and $line =~ //o) {
549 0           $self->_pushback($line);
550 0           $self->_process_tu();
551 0           $line = $self->_readline();
552             }
553              
554             # Sort the sequences
555 0           @{$self->{_sequences}} = sort {
556 0           my($one, $two) = ( $a, $b );
557 0           ($one) = grep { $_->primary_tag() eq 'source' } $one->get_SeqFeatures();
  0            
558 0           ($two) = grep { $_->primary_tag() eq 'source' } $two->get_SeqFeatures();
  0            
559 0 0 0       return 0 unless defined $one and defined $two;
560 0           ($one) = sort { $a <=> $b } $one->get_tagset_values(qw/end5 end3/);
  0            
561 0           ($two) = sort { $a <=> $b } $two->get_tagset_values(qw/end5 end3/);
  0            
562 0           return $one <=> $two;
563 0           } @{$self->{_sequences}};
  0            
564              
565 0 0         if($line =~ /<\/PROTEIN_CODING>/o) {
566 0           return;
567             }
568              
569 0           $self->throw("Reached end of _process_protein_coding");
570             }
571              
572              
573             sub _process_rna_genes
574             {
575 0     0     my ($self) = @_;
576 0           my $line = $self->_readline();
577              
578 0 0         if($line =~ //o) {
579 0           while($line !~ /<\/RNA_GENES>/o) {
580 0           $line = $self->_readline();
581             }
582             } else {
583 0           $self->throw("Bio::SeqIO::tigr::_process_rna_genes called ",
584             "but no in the stream");
585             }
586             }
587              
588             sub _process_misc_info
589             {
590 0     0     my ($self) = @_;
591 0           my $line = $self->_readline();
592              
593 0 0         if($line =~ //o) {
594 0           while($line !~ /<\/MISC_INFO>/o) {
595 0           $line = $self->_readline();
596             }
597             } else {
598 0           $self->throw("Bio::SeqIO::tigr::_process_misc_info called ",
599             "but no in the stream");
600             }
601             }
602              
603             sub _process_repeat_list
604             {
605 0     0     my ($self) = @_;
606 0           my $line = $self->_readline();
607              
608 0 0         if($line =~ //o) {
609 0           while($line !~ /<\/REPEAT_LIST>/o) {
610 0           $line = $self->_readline();
611             }
612             } else {
613 0           $self->throw("Bio::SeqIO::tigr::_process_repeat_list called ",
614             "but no in the stream");
615             }
616             }
617              
618             sub _process_tiling_path
619             {
620 0     0     my($self) = @_;
621 0           my $line = $self->_readline();
622              
623              
624 0 0         if($line =~ //o) {
625 0           while($line !~ /<\/TILING_PATH>/o) {
626 0           $line = $self->_readline();
627             }
628             } else {
629 0           $self->throw("Bio::SeqIO::tigr::_process_repeat_list called ",
630             "but no in the stream");
631             }
632             }
633              
634             sub _process_scaffold
635             {
636 0     0     my ($self) = @_;
637 0           my $line;
638              
639             # for now we just skip them
640 0           $line = $self->_readline();
641 0 0         return if $line !~ //o;
642 0   0       do {
643 0           $line = $self->_readline();
644             } while(defined($line) && $line !~ /<\/SCAFFOLD>/o);
645             }
646              
647             sub _process_tu
648             {
649 0     0     my($self) = @_;
650 0           my $line = $self->_readline();
651              
652             try {
653 0     0     my $tu = Bio::Seq::RichSeq->new(-strand => 1);
654 0           $tu->species( $self->{_assembly}->{species} );
655              
656             # Add the source tag, so we can add the GO annotations to it
657 0           $tu->add_SeqFeature(Bio::SeqFeature::Generic->new(-source_tag => 'TIGR', -primary_tag => 'source'));
658            
659 0 0         if($line !~ //o) {
660 0           $self->throw("Process_tu called when no tag");
661             }
662              
663 0           $line = $self->_readtag();
664 0 0         if ($line =~ /([\w\.]+)<\/FEAT_NAME>/o) {
665 0           $tu->accession_number($1);
666 0           $tu->add_secondary_accession($1);
667 0           $line = $self->_readtag();
668             } else {
669 0           $self->throw("Invalid Feat_Name");
670             }
671              
672 0           while($line =~ //o) {
673             # ignore
674 0           $line = $self->_readtag();
675             }
676            
677 0           while($line =~ /\s*([\w\.]+)\s*<\/CHROMO_LINK>/o) {
678 0           $tu->add_secondary_accession($1);
679 0           $line = $self->_readtag();
680             }
681              
682 0 0         if ($line =~ /([^>]*)<\/DATE>/o) {
683 0 0 0       $tu->add_date($1) if $1 and $1 !~ /^\s*$/o;
684 0           $line = $self->_readline();
685             } else {
686             #$self->throw("Invalid Date: $line");
687             }
688              
689 0 0         if ($line =~ //o) {
690 0           $self->_pushback($line);
691 0           $self->_process_gene_info($tu);
692 0           $line = $self->_readline();
693             } else {
694 0           $self->throw("Invalid Gene_Info");
695             }
696              
697 0           my $source;
698             my $end5;
699 0           my $end3;
700 0 0         if($line =~ //o) {
701 0           $self->_pushback($line);
702 0           my $cs = $self->_process_coordset();
703            
704 0           $end5 = $cs->{end5};
705 0           $end3 = $cs->{end3};
706              
707 0           my $length = $end3 - $end5;
708 0           my $strand = $length <=> 0;
709 0           $length = $length * $strand;
710 0           $length++; # Correct for starting at 1, not 0
711              
712             # Add X filler sequence
713 0           $tu->seq('X' x $length);
714              
715             # Get the source tag:
716 0           my($source) = grep { $_->primary_tag() eq 'source' } $tu->get_SeqFeatures();
  0            
717              
718             # Set the start and end values
719 0           $source->start(1);
720 0           $source->end($length);
721 0           $source->strand(1);
722              
723             # Add a bunch of tags to it
724 0           $source->add_tag_value(clone => $self->{_assembly}->{clone});
725 0           $source->add_tag_value(clone_name => $self->{_assembly}->{clone_name});
726 0           $source->add_tag_value(end5 => $end5);
727 0           $source->add_tag_value(end3 => $end3);
728 0           $source->add_tag_value(chromosome => $self->{_assembly}->{chromosome});
729 0 0         $source->add_tag_value(strand => ( $strand == 1 ? 'positive' : 'negative' ));
730              
731 0           $line = $self->_readline();
732             } else {
733 0           $self->throw("Invalid Coordset");
734             }
735              
736 0 0         if($line =~ /]*>/o) {
737 0           do {
738 0           $self->_pushback($line);
739 0           $self->_process_model($tu, $end5, $end3);
740 0           $line = $self->_readline();
741             } while($line =~ /]*>/o);
742 0           $self->_pushback($line);
743 0           $line = $self->_readtag();
744             } else {
745 0           $self->throw("Expected not found");
746             }
747            
748 0 0         if($line =~ //o) {
749 0           my @chunks;
750 0           $line = $self->_readline();
751 0           while ($line =~ /^\s*([ACGT]+)\s*$/o) {
752 0           push( @chunks, $1 );
753 0           $line = $self->_readline();
754             }
755             # $line = $self->_readline();
756             }
757            
758 0 0         if($line =~ //o) {
759 0           $line = $self->_readtag();
760             }
761            
762 0           while($line =~ /]*>[^<]*<\/URL>/o) {
763 0           $line = $self->_readtag();
764             }
765            
766 0 0         if($line =~ /<\/TU>/o) {
767 0           push(@{$self->{_sequences}}, $tu);
  0            
768 0           return;
769             } else {
770 0           $self->throw("Expected not found: $line");
771             }
772             } catch Bio::Root::OutOfRange with {
773 0     0     my $E = shift;
774 0           $self->warn(sprintf("One sub location of a sequence is invalid near line $.\: %s", $E->text()));
775 0           $line = $self->_readline() until $line =~ /<\/TU>/o;
776 0           return;
777 0           };
778             }
779              
780             sub _process_gene_info
781             {
782 0     0     my($self, $tu) = @_;
783 0           my $line = $self->_readline();
784              
785 0 0         $self->throw("Invalid Gene Info: $line") if $line !~ //o;
786 0           $line = $self->_readline();
787              
788 0 0         if($line =~ /\s*([\w\.]+)\s*<\/LOCUS>/o) {
    0          
789 0           $tu->accession_number($1);
790 0           $tu->add_secondary_accession($1);
791 0           $line = $self->_readline();
792             } elsif( $line =~ /.*<\/LOCUS>/o) {
793             # We should throw an error, but TIGR doesn't alwasy play
794             # nice with adhering to their dtd
795 0           $line = $self->_readtag();
796             } else {
797             #$self->throw("Invalid Locus: $line");
798             }
799              
800 0 0         if($line =~ /\s*([\w\.]+)\s*<\/ALT_LOCUS>/o) {
801 0           $tu->accession_number($1);
802 0           $tu->add_secondary_accession($1);
803 0           $line = $self->_readline();
804             }
805              
806 0 0         if($line =~ /\s*([\w\.]+)\s*<\/PUB_LOCUS>/o) {
    0          
807 0           $tu->accession_number($1);
808 0           $tu->add_secondary_accession($1);
809 0           $line = $self->_readtag();
810             } elsif( $line =~ /.*<\/PUB_LOCUS>/o) {
811 0           $line = $self->_readtag();
812             # $self->throw("Invalid Pub_Locus");
813             }
814              
815 0 0         if($line =~ /.*<\/GENE_NAME>/o) {
816             # Skip the GENE_NAME
817 0           $line = $self->_readtag();
818             }
819              
820 0 0         if(my($attr, $value) = ($line =~ /]*)>([^>]+)<\/COM_NAME>/o)) {
821             #%attribs = ($attr =~ /(\w+)\s*=\s+"(.*?)"/og);
822             #$geneinfo->{'CURATED'} = $attribs{CURATED};
823             #$geneinfo->{IS_PRIMARY} = $attribs{IS_PRIMARY}
824             # TODO: add a tag on sources for curated
825 0           $tu->desc($value);
826 0           $line = $self->_readtag();
827             } else {
828 0           $self->throw("invalid com_name: $line");
829             }
830              
831 0           while($line =~ /([^<]+)<\/COMMENT>/o) {
832 0           my $comment = Bio::Annotation::Comment->new(
833             -text => $1
834             );
835 0           $tu->annotation()->add_Annotation('comment', $comment);
836 0           $line = $self->_readtag();
837             }
838              
839 0           while($line =~ /([^<]+)<\/PUB_COMMENT>/o) {
840 0           my $comment = Bio::Annotation::Comment->new(
841             -text => $1
842             );
843 0           $tu->annotation()->add_Annotation('comment', $comment);
844 0           $line = $self->_readtag();
845             }
846              
847 0 0         if($line =~ /([\w\-\\\.]+)<\/EC_NUM>/o) {
848             #$geneinfo->{'EC_NUM'} = $1;
849 0           $line = $self->_readtag();
850             }
851              
852 0 0         if($line =~ /\s*([^<]+)\s*<\/GENE_SYM>/o) {
853             #$tu->add_secondary_accession($1);
854 0           $line = $self->_readtag();
855             }
856              
857 0 0         if($line =~ /([^>]+)<\/IS_PSEUDOGENE>/o) {
858             #$geneinfo->{'IS_PSEUDOGENE'} = $1;
859 0           $line = $self->_readtag();
860             } else {
861 0           $self->throw("invalid is_pseudogene: $line");
862             }
863              
864 0 0         if($line =~ /
865 0           $line = $self->_readtag();
866             }
867              
868 0 0         if($line =~ /([^>]+)<\/DATE>/o) {
869             #$geneinfo->{'DATE'} = $1;
870 0           $line = $self->_readtag();
871             }
872              
873 0           while($line =~ //o) {
874             # Get the source tag
875 0           my($source) = grep { $_->primary_tag() eq 'source' } $tu->get_SeqFeatures();
  0            
876              
877 0           my @ids = ( $line =~ /()/gso);
878 0           foreach my $go (@ids) {
879 0           my($assignment) = ($go =~ //os);
880 0           my($term) = ($go =~ /([^<]+)<\/GO_TERM>/os);
881 0           my($type) = ($go =~ /([^<]+)<\/GO_TYPE>/os);
882             # TODO: Add GO annotation
883 0 0 0       if(defined $type and defined $assignment and defined $term) {
      0        
884             # Add the GO Annotation
885 0           $source->add_tag_value(
886             GO => "ID: $assignment; Type: $type; $term"
887             );
888             }
889             }
890 0           $line = $self->_readtag();
891             }
892            
893 0 0         if($line =~ /<\/GENE_INFO/o) {
894 0           return;
895             }
896              
897 0           $self->throw("unexpected end of gene_info");
898             }
899              
900             sub _build_location
901             {
902 0     0     my($self, $end5, $end3, $length, $cs) = @_;
903            
904             # Find the start and end of the location
905             # relative to the sequence.
906 0           my $start = abs( $end5 - $cs->{end5} ) + 1;
907 0           my $end = abs( $end5 - $cs->{end3} ) + 1;
908              
909             # Do some bounds checking:
910 0 0         if( $start < 1 ) {
    0          
    0          
911 0           throw Bio::Root::OutOfRange(
912             -text => "locations' start( $start) must be >= 1"
913             );
914             } elsif( $end > $length ) {
915 0           throw Bio::Root::OutOfRange(
916             -text => "locations' end( $end ) must be <= length( $length )"
917             );
918             } elsif( $start > $end ) {
919 0           throw Bio::Root::OutOfRange(
920             -text => "locations' start ( $start ) must be < end ( $end ) $end5, $end3, $cs->{end5}, $cs->{end3}"
921             );
922             }
923              
924 0           return Bio::Location::Simple->new( -start => $start, -end => $end, -strand => 1 );
925             }
926              
927             sub _process_model
928             {
929 0     0     my($self, $tu, $end5, $end3) = @_;
930 0           my $line;
931 0           my( $source ) = grep { $_->primary_tag() eq 'source' } $tu->get_SeqFeatures();
  0            
932 0           my $model = Bio::SeqFeature::Generic->new(
933             -source_tag => 'TIGR',
934             -primary_tag => 'MODEL',
935             );
936              
937 0           $line = $self->_readline();
938 0 0         if($line !~ /]+)>/o) {
939 0           $self->throw("Invalid Model: $line")
940             }
941 0           my %attribs = ($1 =~ /(\w+)\s*=\s*"([^"]*)"/og);
942             #$model->{'CURATED'} = $attribs{'CURATED'};
943             # TODO: Add tag to model
944 0           $line = $self->_readline();
945              
946 0 0         if($line =~ /\s*([\w\.]+)\s*<\/FEAT_NAME>/o) {
947 0           $model->add_tag_value( feat_name => $1 );
948 0           $tu->add_secondary_accession($1);
949 0           $line = $self->_readline();
950             } else {
951 0           $self->throw("Invalid Feature Name: $line");
952             }
953              
954 0 0         if($line =~ /\s*([\w\.]+)\s*<\/PUB_LOCUS>/o) {
955 0           $model->add_tag_value( pub_locus => $1 );
956 0           $tu->add_secondary_accession($1);
957 0           $line = $self->_readline();
958             } else {
959             # $self->throw("Invalid Pub_Locus: $line");
960             }
961              
962 0 0         if($line =~ //o) {
963 0           $self->_pushback($line);
964 0           $self->_process_cdna_support( $model );
965 0           $line = $self->_readline();
966             }
967              
968 0           while($line =~ /([^>]+)<\/CHROMO_LINK>/o) {
969 0           $model->add_tag_value( chromo_link => $1 );
970 0           $line = $self->_readline();
971             }
972              
973 0 0         if($line =~ /([^>]+)<\/DATE>/o) {
974 0           $line = $self->_readline();
975             } else {
976 0           $self->throw("Invalid Date: $line");
977             }
978              
979 0 0         if($line =~ //o) {
980 0           $self->_pushback($line);
981 0           my $cs = $self->_process_coordset();
982 0           my $loc = $self->_build_location($end5, $end3, $tu->length(), $cs);
983            
984 0           $model->start( $loc->start() );
985 0           $model->end( $loc->end() );
986 0           $line = $self->_readline();
987             } else {
988 0           $self->throw("Invalid Coordset: $line");
989             }
990              
991 0           my $exon = Bio::SeqFeature::Generic->new(
992             -source_tag => 'TIGR',
993             -primary_tag => 'EXON',
994             -location => Bio::Location::Split->new(),
995             -tags => [ locus => $tu->accession_number() ],
996             );
997 0           $exon->add_tag_value( model => $model->get_tag_values('feat_name') );
998              
999 0           my $cds = Bio::SeqFeature::Generic->new(
1000             -source_tag => 'TIGR',
1001             -primary_tag => 'CDS',
1002             -location => Bio::Location::Split->new(),
1003             -tags => [ locus => $tu->accession_number() ],
1004             );
1005 0           $cds->add_tag_value( model => $model->get_tag_values('feat_name') );
1006 0           my $utr = [];
1007              
1008 0 0         if($line =~ //o) {
1009 0           do {
1010 0           $self->_pushback($line);
1011 0           $self->_process_exon( $tu, $exon, $cds, $utr, $end5, $end3 );
1012 0           $line = $self->_readline();
1013             } while($line =~ //o);
1014             } else {
1015 0           $self->throw("Required missing");
1016             }
1017            
1018 0           until($line =~ /<\/MODEL>/o) {
1019 0           $line = $self->_readline();
1020             }
1021              
1022              
1023             $_->add_tag_value( model => $model->get_tag_values('feat_name') )
1024 0           foreach @$utr;
1025              
1026             # Add the model, EXONs, CDS, and UTRs
1027 0 0 0       $tu->add_SeqFeature($model) if $model and $model->start() >= 1;
1028 0 0 0       $tu->add_SeqFeature($exon) if $exon and scalar($exon->location()->each_Location()) >= 1;
1029 0 0 0       $tu->add_SeqFeature($cds) if $cds and scalar($cds->location()->each_Location()) >= 1;
1030 0           $tu->add_SeqFeature(@$utr);
1031              
1032 0           return;
1033             }
1034              
1035             sub _process_cdna_support
1036             {
1037 0     0     my($self, $model) = @_;
1038 0           my $line = $self->_readline();
1039              
1040 0 0         if($line !~ //o) {
1041 0           $self->throw("Bio::SeqIO::tigr::_process_cdna_support called ",
1042             "but no in the stream");
1043             }
1044              
1045 0           $line = $self->_readline();
1046              
1047 0           while( $line =~ /]+)>(.*)<\/ACCESSION>/o) {
1048             # Save the text
1049 0           my $desc = $2;
1050            
1051             # Get the element's attributes
1052 0           my %attribs = ($1 =~ /(\w+)\s*=\s*"([^"]*)"/og);
1053              
1054             # Add the tag to the model
1055 0           $model->add_tag_value(
1056             cdna_support => "DBXRef: $attribs{DBXREF}; $desc"
1057             );
1058              
1059 0           $line = $self->_readline();
1060             }
1061              
1062 0 0         if( $line =~ /<\/CDNA_SUPPORT>/o) {
1063 0           return;
1064             }
1065 0           $self->throw("reached end of _process_cdna_support");
1066             }
1067              
1068              
1069             sub _process_exon
1070             {
1071 0     0     my($self, $tu, $exon, $cds, $utr, $end5, $end3 ) = @_;
1072 0           my $line = $self->_readline();
1073              
1074 0 0         if($line !~ //o) {
1075 0           $self->throw("Bio::SeqIO::tigr::_process_exon called ",
1076             "but no in the stream");
1077             }
1078              
1079 0           $line = $self->_readtag();
1080 0 0         if($line =~ /([^<]+)<\/FEAT_NAME>/o) {
1081             # Ignore
1082 0           $line = $self->_readtag();
1083             } else {
1084 0           $self->throw("Required missing");
1085             }
1086              
1087 0 0         if($line =~ /([^<]+)<\/DATE>/o) {
1088             # Ignore
1089 0           $line = $self->_readtag();
1090             } else {
1091 0           $self->throw("Required missing");
1092             }
1093              
1094 0 0         if($line =~ //o) {
1095 0           $self->_pushback($line);
1096 0           my $cs = $self->_process_coordset();
1097 0           my $loc = $self->_build_location($end5, $end3, $tu->length(), $cs);
1098 0           $exon->location()->add_sub_Location($loc);
1099 0           $line = $self->_readline();
1100             } else {
1101 0           $self->throw("Required missing");
1102             }
1103              
1104 0 0         if($line =~ //o) {
1105 0           $self->_pushback($line);
1106 0           $self->_process_cds($tu, $end5, $end3, $cds);
1107 0           $line = $self->_readline();
1108             }
1109              
1110 0 0         if($line =~ //o) {
1111 0           $self->_pushback($line);
1112 0           $self->_process_utrs($tu, $end5, $end3, $utr);
1113 0           $line = $self->_readline();
1114             }
1115              
1116 0 0         if($line =~ /<\/EXON>/o) {
1117 0           return;
1118             }
1119              
1120 0           $self->throw("Reached End of Bio::SeqIO::tigr::_process_exon");
1121             }
1122              
1123             sub _process_cds
1124             {
1125 0     0     my($self, $tu, $end5, $end3, $cds) = @_;
1126 0           my $line = $self->_readline();
1127              
1128 0 0         if($line !~ //o) {
1129 0           $self->throw("Bio::SeqIO::tigr::_process_cda_support called ",
1130             "but no in the stream");
1131             }
1132            
1133 0           $line = $self->_readtag();
1134 0 0         if($line =~ /([^<]+)<\/FEAT_NAME>/o) {
1135             #$cds->{'FEAT_NAME'} = $1;
1136 0           $line = $self->_readtag();
1137             } else {
1138 0           $self->throw("Required missing");
1139             }
1140              
1141 0 0         if($line =~ /([^<]+)<\/DATE>/o) {
1142             #$cds->{'DATE'} = $1;
1143 0           $line = $self->_readtag();
1144             } else {
1145 0           $self->throw("Required missing");
1146             }
1147              
1148 0 0         if($line =~ //o) {
1149 0           $self->_pushback($line);
1150 0           my $cs = $self->_process_coordset();
1151 0           my $loc = $self->_build_location($end5, $end3, $tu->length(), $cs);
1152 0           $cds->location()->add_sub_Location($loc);
1153 0           $line = $self->_readline();
1154             } else {
1155 0           $self->throw("Required missing");
1156             }
1157              
1158 0 0         if($line =~ /<\/CDS>/o) {
1159 0           return;
1160             }
1161              
1162 0           $self->throw("Reached onf of Bio::SeqIO::tigr::_process_cds");
1163             }
1164              
1165             sub _process_utrs
1166             {
1167 0     0     my($self, $tu, $end5, $end3, $utrs) = @_;
1168 0           my $line = $self->_readline();
1169              
1170 0 0         if($line !~ /
1171 0           $self->throw("Bio::SeqIO::tigr::_process_utrs called but no ",
1172             " found in stream");
1173             }
1174              
1175 0           $line = $self->_readline();
1176 0           while($line !~ /<\/UTRS>/o) {
1177 0           $self->_pushback($line);
1178 0 0         if($line =~ //o) {
    0          
    0          
1179 0           $self->_process_left_utr($tu, $end5, $end3, $utrs);
1180             } elsif ($line =~ //o) {
1181 0           $self->_process_right_utr($tu, $end5, $end3, $utrs);
1182             } elsif ($line =~ //o) {
1183 0           $self->_process_ext_utr($tu, $end5, $end3, $utrs);
1184             } else {
1185 0           $self->throw("Unexpected tag");
1186             }
1187            
1188 0           $line = $self->_readline();
1189             }
1190              
1191 0 0         if($line =~ /<\/UTRS>/o) {
1192 0           return $utrs;
1193             }
1194 0           $self->throw("Reached end of Bio::SeqIO::tigr::_process_utrs");
1195             }
1196              
1197             sub _process_left_utr
1198             {
1199 0     0     my($self, $tu, $end5, $end3, $utrs) = @_;
1200 0           my $line = $self->_readline();
1201 0           my $coordset;
1202              
1203 0 0         if($line !~ //o) {
1204 0           $self->throw("Bio::SeqIO::tigr::_process_left_utr called but ",
1205             "no found in stream");
1206             }
1207              
1208 0           $line = $self->_readtag();
1209 0 0         if($line =~ //o) {
1210 0           $self->_pushback($line);
1211 0           my $cs = $self->_process_coordset();
1212 0           my $loc = $self->_build_location($end5, $end3, $tu->length(), $cs);
1213              
1214 0           push(@$utrs, Bio::SeqFeature::Generic->new(
1215             -source_tag => 'TIGR',
1216             -primary_tag => 'LEFT_UTR',
1217             -strand => 1,
1218             -start => $loc->start(),
1219             -end => $loc->end()
1220             ));
1221              
1222 0           $line = $self->_readline();
1223             } else {
1224 0           $self->throw("Required missing");
1225             }
1226              
1227 0 0         if($line =~ /<\/LEFT_UTR>/o) {
1228 0           return;
1229             }
1230 0           $self->throw("Reached end of Bio::SeqIO::tigr::_process_left_utr");
1231             }
1232              
1233             sub _process_right_utr
1234             {
1235 0     0     my($self, $tu, $end5, $end3, $utrs) = @_;
1236 0           my $line = $self->_readline();
1237 0           my $coordset;
1238              
1239 0 0         if($line !~ //o) {
1240 0           $self->throw("Bio::SeqIO::tigr::_process_right_utr called but ",
1241             "no found in stream");
1242             }
1243              
1244 0           $line = $self->_readtag();
1245 0 0         if($line =~ //o) {
1246 0           $self->_pushback($line);
1247 0           $coordset = $self->_process_coordset();
1248 0           $self->_pushback($line);
1249 0           my $cs = $self->_process_coordset();
1250 0           my $loc = $self->_build_location($end5, $end3, $tu->length(), $cs);
1251              
1252 0           push(@$utrs, Bio::SeqFeature::Generic->new(
1253             -source_tag => 'TIGR',
1254             -primary_tag => 'RIGHT_UTR',
1255             -strand => 1,
1256             -start => $loc->start(),
1257             -end => $loc->end()
1258             ));
1259              
1260 0           $line = $self->_readline();
1261             } else {
1262 0           $self->throw("Required missing");
1263             }
1264              
1265 0 0         if($line =~ /<\/RIGHT_UTR>/o) {
1266 0           return $coordset;
1267             }
1268 0           $self->throw("Reached end of Bio::SeqIO::tigr::_process_right_utr");
1269             }
1270              
1271             sub _process_ext_utr
1272             {
1273 0     0     my($self, $tu, $end5, $end3, $utrs) = @_;
1274 0           my $line = $self->_readline();
1275 0           my $coordset;
1276              
1277 0 0         if($line !~ //o) {
1278 0           $self->throw("Bio::SeqIO::tigr::_process_ext_utr called but ",
1279             "no found in stream");
1280             }
1281              
1282 0           $line = $self->_readtag();
1283 0 0         if($line =~ //o) {
1284 0           $self->_pushback($line);
1285 0           my $cs = $self->_process_coordset();
1286 0           my $loc = $self->_build_location($end5, $end3, $tu->length(), $cs);
1287              
1288 0           push(@$utrs, Bio::SeqFeature::Generic->new(
1289             -source_tag => 'TIGR',
1290             -primary_tag => 'EXTENDED_UTR',
1291             -strand => 1,
1292             -start => $loc->start(),
1293             -end => $loc->end()
1294             ));
1295              
1296 0           $line = $self->_readline();
1297             } else {
1298 0           $self->throw("Required missing");
1299             }
1300              
1301 0 0         if($line =~ /<\/EXTENDED_UTR>/o) {
1302 0           return $coordset;
1303             }
1304 0           $self->throw("Reached end of Bio::SeqIO::tigr::_process_ext_utr");
1305             }
1306              
1307             sub _readtag
1308             {
1309 0     0     my($self) = @_;
1310 0           my $line = $self->_readline();
1311 0           chomp($line);
1312              
1313 0           my $tag;
1314 0 0         if(($tag) = ($line =~ /^[^<]*<\/(\w+)/o)) {
1315 0 0         $self->_pushback($1) if $line =~ /<\/$tag>(.+)$/;
1316 0           return "";
1317             }
1318            
1319 0           until(($tag) = ($line =~ /<(\w+)[^>]*>/o)) {
1320 0           $line = $self->_readline();
1321 0           chomp $line;
1322             }
1323              
1324 0           until($line =~ /<\/$tag>/) {
1325 0           $line .= $self->_readline();
1326             }
1327              
1328 0 0         if(my ($val) = ($line =~ /(<$tag.*>.*?<\/$tag>)/s)) {
1329 0 0         if($line =~ /<\/$tag>\s*(\w+[\s\w]*?)\s*$/s) {
1330 0           $self->_pushback($1)
1331             }
1332 0           return $val;
1333             }
1334 0           $self->throw("summerror");
1335             }
1336              
1337             sub _readline
1338             {
1339 0     0     my($self) = @_;
1340 0           my $line;
1341 0   0       do {
1342 0           $line = $self->SUPER::_readline();
1343             } while(defined($line) and $line =~ /^\s*$/o);
1344              
1345 0           return $line;
1346             }
1347              
1348             sub throw
1349             {
1350 0     0 1   my($self, @s) = @_;
1351 0           my $string = "[$.]" . join('', @s);
1352 0           $self->SUPER::throw($string);
1353             }
1354              
1355             1;