Mercurial > repos > mahtabm > ensembl
comparison variant_effect_predictor/Bio/SeqIO/game.pm @ 0:1f6dce3d34e0
Uploaded
author | mahtabm |
---|---|
date | Thu, 11 Apr 2013 02:01:53 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1f6dce3d34e0 |
---|---|
1 # $Id: game.pm,v 1.26.2.1 2003/06/28 22:23:15 jason Exp $ | |
2 # | |
3 # BioPerl module for Bio::SeqIO::game | |
4 # | |
5 # Cared for by Brad Marshall <bradmars@yahoo.com> | |
6 # | |
7 # Copyright Ewan Birney & Lincoln Stein & Brad Marshall | |
8 # | |
9 # You may distribute this module under the same terms as perl itself | |
10 # _history | |
11 # June 25, 2000 written by Brad Marshall | |
12 # | |
13 # POD documentation - main docs before the code | |
14 | |
15 =head1 NAME | |
16 | |
17 Bio::SeqIO::game - Parses GAME XML 0.1 and higher into and out of Bio::Seq objects. | |
18 | |
19 =head1 SYNOPSIS | |
20 | |
21 To use this module you need XML::Parser, XML::Parser::PerlSAX | |
22 and XML::Writer. | |
23 | |
24 Do not use this module directly. Use it via the Bio::SeqIO class. | |
25 | |
26 =head1 DESCRIPTION | |
27 | |
28 This object can transform Bio::Seq objects to and from bioxml seq, | |
29 computation, feature and annotation dtds,versions 0.1 and higher. | |
30 These can be found at http://www.bioxml.org/dtds/current. It does | |
31 this using the idHandler, seqHandler and featureHandler modules you | |
32 should have gotten with this one. | |
33 | |
34 The idea is that any bioxml features can be turned into bioperl | |
35 annotations. When Annotations and computations are parsed in, they | |
36 gain additional info in the bioperl SeqFeature tag attribute. These | |
37 can be used to reconstitute a computation or annotation by the bioxml | |
38 with the bx-handler module when write_seq is called. | |
39 | |
40 If you use this to write SeqFeatures that were not generated from | |
41 computations or annotations, it will output a list of bioxml features. | |
42 Some data may be lost in this step, since bioxml features just have a | |
43 span, type and description - nothing about the anlysis performed. | |
44 | |
45 =head1 FEEDBACK | |
46 | |
47 =head2 Mailing Lists | |
48 | |
49 User feedback is an integral part of the evolution of this | |
50 and other Bioperl modules. Send your comments and suggestions preferably | |
51 to one of the Bioperl mailing lists. | |
52 Your participation is much appreciated. | |
53 | |
54 bioperl-l@bioperl.org - Technical bioperl discussion | |
55 bioxml-dev@bioxml.org - Technical discussion - Moderate volume | |
56 bioxml-announce@bioxml.org - General Announcements - Pretty dead | |
57 http://www.bioxml.org/MailingLists/ - About the mailing lists | |
58 | |
59 =head1 AUTHOR - Brad Marshall & Ewan Birney & Lincoln Stein | |
60 | |
61 Email: bradmars@yahoo.com | |
62 birney@sanger.ac.uk | |
63 lstein@cshl.org | |
64 | |
65 | |
66 =head1 CONTRIBUTORS | |
67 | |
68 Jason Stajich E<lt>jason@bioperl.orgE<gt> | |
69 | |
70 =head1 APPENDIX | |
71 | |
72 The rest of the documentation details each of the object | |
73 methods. Internal methods are usually preceded with a _ | |
74 | |
75 =cut | |
76 | |
77 # Let the code begin... | |
78 | |
79 package Bio::SeqIO::game; | |
80 use vars qw(@ISA); | |
81 use strict; | |
82 # Object preamble - inherits from Bio::Root::Object | |
83 | |
84 use Bio::SeqIO; | |
85 use Bio::SeqIO::game::seqHandler; | |
86 use Bio::SeqIO::game::featureHandler; | |
87 use Bio::SeqIO::game::idHandler; | |
88 use XML::Parser::PerlSAX; | |
89 use Bio::SeqFeature::Generic; | |
90 use XML::Writer; | |
91 | |
92 use Bio::Seq; | |
93 | |
94 @ISA = qw(Bio::SeqIO); | |
95 | |
96 | |
97 sub _initialize { | |
98 my($self,@args) = @_; | |
99 $self->SUPER::_initialize(@args); | |
100 my $xmlfile = ""; | |
101 $self->{'counter'} = 0; | |
102 $self->{'id_counter'} = 1; | |
103 $self->{'leftovers'} = undef; | |
104 $self->{'header'} = undef; | |
105 $self->{'chunkable'} = undef; | |
106 $self->{'xmldoc'} = undef; | |
107 | |
108 $self->_export_subfeatures(1); | |
109 $self->_group_subfeatures(1); | |
110 $self->_subfeature_types('exons', 'promoters','poly_A_sites', | |
111 'utrs','introns','sub_SeqFeature'); | |
112 | |
113 # filehandle is stored by superclass _initialize | |
114 } | |
115 | |
116 | |
117 =head2 _export_subfeatures | |
118 | |
119 Title : _export_subfeatures | |
120 Usage : $obj->_export_subfeatures | |
121 Function: export all subfeatures (also in the geneprediction structure) | |
122 Returns : value of _export_subfeatures | |
123 Args : newvalue (optional) | |
124 | |
125 =cut | |
126 | |
127 sub _export_subfeatures{ | |
128 my $obj = shift; | |
129 if( @_ ) { | |
130 my $value = shift; | |
131 $obj->{'_export_subfeatures'} = $value; | |
132 } | |
133 return $obj->{'_export_subfeatures'}; | |
134 | |
135 } | |
136 | |
137 =head2 _group_subfeatures | |
138 | |
139 Title : _group_subfeatures | |
140 Usage : $obj->_group_subfeatures | |
141 Function: Groups all subfeatures in separate feature_sets | |
142 Returns : value of _group_subfeatures | |
143 Args : newvalue (optional) | |
144 | |
145 =cut | |
146 | |
147 sub _group_subfeatures{ | |
148 my $obj = shift; | |
149 if( @_ ) { | |
150 my $value = shift; | |
151 $obj->{'_group_subfeatures'} = $value; | |
152 } | |
153 return $obj->{'_group_subfeatures'}; | |
154 } | |
155 | |
156 =head2 _subfeature_types | |
157 | |
158 Title : _subfeature_types | |
159 Usage : $obj->_subfeature_types | |
160 Function: array of all possible subfeatures, it should be a | |
161 name of a function which | |
162 : returns an arrau of sub_seqfeatures when called: | |
163 @array = $feature->subfeaturetype() | |
164 Returns : array of _subfeature_types | |
165 Args : array of subfeature types (optional) | |
166 | |
167 =cut | |
168 | |
169 sub _subfeature_types{ | |
170 my $obj = shift; | |
171 if( @_ ) { | |
172 my @values = @_; | |
173 $obj->{'_subfeature_types'} = \@values; | |
174 } | |
175 return @{$obj->{'_subfeature_types'}}; | |
176 | |
177 } | |
178 | |
179 =head2 _add_subfeature_type | |
180 | |
181 Title : _add_subfeature_type | |
182 Usage : $obj->_add_subfeature_type | |
183 Function: add one possible subfeature, it should be a name of a function which | |
184 : returns an arrau of sub_seqfeatures when called: @array = $feature->subfeaturetyp() | |
185 Returns : 1 | |
186 Args : one subfeature type (optional) | |
187 | |
188 =cut | |
189 | |
190 sub _add_subfeature_type{ | |
191 my $obj = shift; | |
192 if( @_ ) { | |
193 my @values = @_; | |
194 push @{$obj->{'_subfeature_types'}}, @values; | |
195 } | |
196 return 1; | |
197 | |
198 } | |
199 | |
200 | |
201 =head2 next_seq | |
202 | |
203 Title : next_seq | |
204 Usage : $seq = $stream->next_seq() | |
205 Function: returns the next sequence in the stream | |
206 Returns : Bio::Seq object | |
207 Args : NONE | |
208 | |
209 =cut | |
210 | |
211 sub next_seq { | |
212 my $self = shift; | |
213 | |
214 | |
215 # The header is the top level stuff in the XML file. | |
216 # IE before the first <bx-seq:seq> tag. | |
217 # If you don't include this in each 'chunk', the | |
218 # parser will barf. | |
219 my $header; | |
220 unless ($self->{'header'}) { | |
221 while (my $next_line = $self->_readline) { | |
222 if($next_line=~/<bx-seq:seq?/) { | |
223 $header .= $`; | |
224 $self->{'header'}=$header; | |
225 $self->{'leftovers'} .= "<bx-seq:seq".$'; | |
226 last; | |
227 } else { | |
228 $header .= $next_line; | |
229 } | |
230 } | |
231 if ($self->{'header'}=~m|<bx-game:flavor>.*chunkable.*</bx-game:flavor>|) { | |
232 $self->{'chunkable'}=1; | |
233 } | |
234 | |
235 } | |
236 | |
237 my $not_top_level; | |
238 my $xmldoc; | |
239 my $seq; | |
240 # If chunkable, we read in the document until the next | |
241 # TOP LEVEL sequence. | |
242 if ($self->{'chunkable'}) { | |
243 $xmldoc = $self->{'header'}.$self->{'leftovers'}; | |
244 while (my $next_line = $self->_readline) { | |
245 # Maintain depth of computations and annotations. | |
246 # We only want TOP LEVEL seqs if chunkable. | |
247 while ($next_line=~ m|<bx-computation:computation|g) { | |
248 $not_top_level++; | |
249 } | |
250 while ($next_line=~ m|<bx-annotation:annotation|g) { | |
251 $not_top_level++; | |
252 } | |
253 while ($next_line=~ m|</bx-computation:computation|g) { | |
254 $not_top_level--; | |
255 } | |
256 while ($next_line=~ m|</bx-annotation:annotation|g) { | |
257 $not_top_level--; | |
258 } | |
259 if($next_line=~/<bx-seq:seq?/) { | |
260 if (!$not_top_level) { | |
261 $xmldoc .= $`; | |
262 $self->{'leftovers'} .= "<bx-seq:seq".$'; | |
263 last; | |
264 } | |
265 } else { | |
266 $xmldoc .= $next_line; | |
267 } | |
268 } | |
269 # Make sure the 'doc chunk' has a closing tag | |
270 # to make the parser happy. | |
271 if (!$xmldoc=~m|</bx-game:game>|){ | |
272 $xmldoc .= "</bx-game:game>"; | |
273 } | |
274 # Grab the TOP LEVEL seq.. | |
275 if ($xmldoc =~ m|</bx-seq:seq|) { | |
276 my $handler = Bio::SeqIO::game::idHandler->new(); | |
277 my $options = {Handler=>$handler}; | |
278 my $parser = XML::Parser::PerlSAX->new($options); | |
279 $self->{'seqs'} = $parser->parse(Source => { String => $xmldoc }); | |
280 } else { # No sequences. | |
281 return 0; | |
282 } | |
283 # Get the seq out of the array. | |
284 $seq = @{$self->{'seqs'}}[0]; | |
285 # If not chunkable, | |
286 # only read document into memory once! | |
287 } elsif (!$self->{'xmldoc'}) { | |
288 $self->{'xmldoc'}=$self->{'header'}.$self->{'leftovers'}; | |
289 while (my $next_line = $self->_readline) { | |
290 $self->{'xmldoc'} .= $next_line; | |
291 } | |
292 $xmldoc=$self->{'xmldoc'}; | |
293 # Get the seq id index. | |
294 if ($xmldoc =~ m|</bx-seq:seq|) { | |
295 my $handler = Bio::SeqIO::game::idHandler->new(); | |
296 my $options = {Handler=>$handler}; | |
297 my $parser = XML::Parser::PerlSAX->new($options); | |
298 $self->{'seqs'} = $parser->parse(Source => { String => $xmldoc }); | |
299 $seq = shift @{$self->{'seqs'}}; | |
300 } else { # No sequences. | |
301 return 0; | |
302 } | |
303 my $seq = @{$self->{'seqs'}}[0]; | |
304 # if we already have the doc in memory, | |
305 # just get the doc. | |
306 } elsif ($self->{'xmldoc'}) { | |
307 $xmldoc=$self->{'xmldoc'}; | |
308 $seq = shift @{$self->{'seqs'}}; | |
309 } | |
310 # If there's more sequences: | |
311 if ($seq) { | |
312 # Get the next seq. | |
313 my $handler = Bio::SeqIO::game::seqHandler->new(-seq => $seq); | |
314 my $options = {Handler=>$handler}; | |
315 my $parser = XML::Parser::PerlSAX->new($options); | |
316 my $pseq = $parser->parse(Source => { String => $xmldoc }); | |
317 # get the features. | |
318 my $fhandler = Bio::SeqIO::game::featureHandler->new($pseq->id(), | |
319 $pseq->length(), | |
320 $pseq->alphabet()); | |
321 $options = {Handler=>$fhandler}; | |
322 | |
323 $parser = XML::Parser::PerlSAX->new($options); | |
324 my $features = $parser->parse(Source => { String => $xmldoc }); | |
325 my $seq = Bio::Seq->new(); | |
326 # Build the Bioperl Seq and return it. | |
327 foreach my $feature (@{$features}) { | |
328 $seq->add_SeqFeature($feature); | |
329 } | |
330 $seq->primary_seq($pseq); | |
331 return $seq; | |
332 } else { | |
333 return 0; | |
334 } | |
335 } | |
336 | |
337 =head2 next_primary_seq | |
338 | |
339 Title : next_primary_seq | |
340 Usage : $seq = $stream->next_primary_seq() | |
341 Function: returns the next primary sequence (ie no seq_features) in the stream | |
342 Returns : Bio::PrimarySeq object | |
343 Args : NONE | |
344 | |
345 =cut | |
346 | |
347 sub next_primary_seq { | |
348 my $self=shift; | |
349 | |
350 # The header is the top level stuff in the XML file. | |
351 # IE before the first <bx-seq:seq> tag. | |
352 # If you don't include this in each 'chunk', the | |
353 # parser will barf. | |
354 my $header; | |
355 unless ($self->{'header'}) { | |
356 while (my $next_line = $self->_readline) { | |
357 if($next_line=~/<bx-seq:seq?/) { | |
358 $header .= $`; | |
359 $self->{'header'}=$header; | |
360 $self->{'leftovers'} .= "<bx-seq:seq".$'; | |
361 last; | |
362 } else { | |
363 $header .= $next_line; | |
364 } | |
365 } | |
366 if ($self->{'header'}=~m|<bx-game:flavor>.*chunkable.*</bx-game:flavor>|) { | |
367 $self->{'chunkable'}=1; | |
368 } | |
369 | |
370 } | |
371 | |
372 my $not_top_level = 0; | |
373 my $xmldoc; | |
374 my $seq; | |
375 # If chunkable, we read in the document until the next | |
376 # TOP LEVEL sequence. | |
377 if ($self->{'chunkable'}) { | |
378 $xmldoc = $self->{'header'}.$self->{'leftovers'}; | |
379 while (my $next_line = $self->_readline) { | |
380 # Maintain depth of computations and annotations. | |
381 # We only want TOP LEVEL seqs if chunkable. | |
382 while ($next_line=~ m|<bx-computation:computation|g) { | |
383 $not_top_level++; | |
384 } | |
385 while ($next_line=~ m|<bx-annotation:annotationn|g) { | |
386 $not_top_level++; | |
387 } | |
388 while ($next_line=~ m|</bx-computation:computation|g) { | |
389 $not_top_level--; | |
390 } | |
391 while ($next_line=~ m|</bx-annotation:annotationn|g) { | |
392 $not_top_level--; | |
393 } | |
394 if($next_line=~/<bx-seq:seq?/) { | |
395 if (!$not_top_level) { | |
396 $xmldoc .= $`; | |
397 $self->{'leftovers'} .= "<bx-seq:seq".$'; | |
398 last; | |
399 } | |
400 } else { | |
401 $xmldoc .= $next_line; | |
402 } | |
403 } | |
404 # Make sure the 'doc chunk' has a closing tag | |
405 # to make the parser happy. | |
406 if (!$xmldoc=~m|</bx-game:game>|){ | |
407 $xmldoc .= "</bx-game:game>"; | |
408 } | |
409 # Grab the TOP LEVEL seq.. | |
410 if ($xmldoc =~ m|</bx-seq:seq|) { | |
411 my $handler = Bio::SeqIO::game::idHandler->new(); | |
412 my $options = {Handler=>$handler}; | |
413 my $parser = XML::Parser::PerlSAX->new($options); | |
414 $self->{'seqs'} = $parser->parse(Source => { String => $xmldoc }); | |
415 } else { # No sequences. | |
416 return 0; | |
417 } | |
418 $seq = @{$self->{'seqs'}}[0]; | |
419 # If not chunkable, | |
420 # only read document into memory once! | |
421 } elsif (!$self->{'xmldoc'}) { | |
422 $self->{'xmldoc'}=$self->{'header'}.$self->{'leftovers'}; | |
423 while (my $next_line = $self->_readline) { | |
424 $self->{'xmldoc'} .= $next_line; | |
425 } | |
426 $xmldoc=$self->{'xmldoc'}; | |
427 # Get the seq id index. | |
428 if ($xmldoc =~ m|</bx-seq:seq|) { | |
429 my $handler = Bio::SeqIO::game::idHandler->new(); | |
430 my $options = {Handler=>$handler}; | |
431 my $parser = XML::Parser::PerlSAX->new($options); | |
432 $self->{'seqs'} = $parser->parse(Source => { String => $xmldoc }); | |
433 $seq = shift @{$self->{'seqs'}}; | |
434 } else { # No sequences. | |
435 return 0; | |
436 } | |
437 my $seq = @{$self->{'seqs'}}[0]; | |
438 # if we already have the doc in memory, | |
439 # just get the doc. | |
440 } elsif ($self->{'xmldoc'}) { | |
441 $xmldoc=$self->{'xmldoc'}; | |
442 $seq = shift @{$self->{'seqs'}}; | |
443 } | |
444 | |
445 #print $xmldoc; | |
446 | |
447 if ($seq) { | |
448 # Get the next seq. | |
449 my $handler = Bio::SeqIO::game::seqHandler->new(-seq => $seq); | |
450 my $options = {Handler=>$handler}; | |
451 my $parser = XML::Parser::PerlSAX->new($options); | |
452 my $pseq = $parser->parse(Source => { String => $xmldoc }); | |
453 return $pseq; | |
454 } else { | |
455 return 0; | |
456 } | |
457 } | |
458 | |
459 | |
460 =head2 write_seq | |
461 | |
462 Title : write_seq | |
463 Usage : Not Yet Implemented! $stream->write_seq(@seq) | |
464 Function: writes the $seq object into the stream | |
465 Returns : 1 for success and 0 for error | |
466 Args : Bio::Seq object | |
467 | |
468 | |
469 =cut | |
470 | |
471 sub write_seq { | |
472 my ($self,@seqs) = @_; | |
473 | |
474 my $bxfeat = "http://www.bioxml.org/dtds/current/feature.dtd"; | |
475 my $bxann = "http://www.bioxml.org/dtds/current/annotation.dtd"; | |
476 my $bxcomp = "http://www.bioxml.org/dtds/current/computation.dtd"; | |
477 my $bxgame = "http://www.bioxml.org/dtds/current/game.dtd"; | |
478 my $bxlink = "http://www.bioxml.org/dtds/current/link.dtd"; | |
479 my $bxseq = "http://www.bioxml.org/dtds/current/seq.dtd"; | |
480 | |
481 my $writer = new XML::Writer(OUTPUT => $self->_fh || \*STDOUT, | |
482 NAMESPACES => 1, | |
483 DATA_MODE => 1, | |
484 DATA_INDENT => 4, | |
485 PREFIX_MAP => { | |
486 '' => '', # to keep undef warnings away in XML::Writer, fill in with something as a default prefix later? | |
487 $bxfeat => 'bx-feature', | |
488 $bxann => 'bx-annotation', | |
489 $bxcomp => 'bx-computation', | |
490 $bxgame => 'bx-game', | |
491 $bxlink => 'bx-link', | |
492 $bxseq => 'bx-seq' | |
493 }); | |
494 $writer->xmlDecl("UTF-8"); | |
495 $writer->doctype("bx-game:game", 'game', $bxgame); | |
496 $writer ->startTag ([$bxgame, 'game']); | |
497 $writer->startTag ([$bxgame, 'flavor']); | |
498 $writer->characters('chunkable'); | |
499 $writer->endTag ([$bxgame, 'flavor']); | |
500 | |
501 foreach my $seq (@seqs) { | |
502 $writer->startTag([$bxseq, 'seq'], | |
503 [$bxseq, 'id'] => $seq->display_id, | |
504 [$bxseq, 'length'] => $seq->length, | |
505 [$bxseq, 'type'] => $seq->alphabet); | |
506 if ($seq->length > 0) { | |
507 $writer->startTag([$bxseq, 'residues']); | |
508 $writer->characters($seq->seq); | |
509 $writer->endTag([$bxseq, 'residues']); | |
510 } | |
511 $writer->endTag([$bxseq, 'seq']); | |
512 | |
513 my @feats = $seq->all_SeqFeatures; | |
514 | |
515 my $features; | |
516 foreach my $feature (@feats) { | |
517 if ($feature->has_tag('annotation_id')) { | |
518 my @ann_id = $feature->each_tag_value('annotation_id'); | |
519 push (@{$features->{'annotations'}->{$ann_id[0]}}, $feature); | |
520 } elsif ($feature->has_tag('computation_id')) { | |
521 my @comp_id = $feature->each_tag_value('computation_id'); | |
522 push (@{$features->{'computations'}->{$comp_id[0]}}, $feature); | |
523 } else { | |
524 push (@{$features->{'everybody_else'}}, $feature); | |
525 } | |
526 } | |
527 foreach my $key (keys %{$features->{'annotations'}}) { | |
528 $writer->startTag([$bxann, 'annotation'], | |
529 [$bxann, 'id']=>$key | |
530 ); | |
531 $writer->startTag([$bxann, 'seq_link']); | |
532 $writer->startTag([$bxlink, 'link']); | |
533 $writer->emptyTag([$bxlink, 'ref_link'], | |
534 [$bxlink, 'ref'] => $seq->display_id()); | |
535 $writer->endTag([$bxlink, 'link']); | |
536 $writer->endTag([$bxann, 'seq_link']); | |
537 $self->__draw_feature_set($writer, $seq, $bxann, "", @{$features->{'annotations'}->{$key}}); | |
538 $writer->endTag([$bxann, 'annotation']); | |
539 } | |
540 | |
541 foreach my $key (keys %{$features->{'computations'}}) { | |
542 $writer->startTag([$bxcomp, 'computation'], | |
543 [$bxcomp, 'id']=>$key | |
544 ); | |
545 $writer->startTag([$bxcomp, 'seq_link']); | |
546 $writer->startTag([$bxlink, 'link']); | |
547 $writer->emptyTag([$bxlink, 'ref_link'], | |
548 [$bxlink, 'ref'] => $seq->display_id()); | |
549 $writer->endTag([$bxlink, 'link']); | |
550 $writer->endTag([$bxcomp, 'seq_link']); | |
551 $self->__draw_feature_set($writer, $seq, $bxcomp, "", @{$features->{'computations'}->{$key}}); | |
552 $writer->endTag([$bxcomp, 'computation']); | |
553 } | |
554 foreach my $feature (@{$features->{'everybody_else'}}) { | |
555 $self->__draw_feature($writer, $feature, $seq, "", | |
556 $self->_export_subfeatures()); | |
557 } | |
558 } | |
559 $writer->endTag([$bxgame, 'game']); | |
560 | |
561 $self->flush if $self->_flush_on_write && defined $self->_fh; | |
562 return 1; | |
563 } | |
564 | |
565 | |
566 #these two subroutines are very specific! | |
567 | |
568 sub __draw_feature_set { | |
569 my ($self, $writer, $seq, $namespace, $parent, @features) = @_; | |
570 my ($feature_set_id); | |
571 | |
572 my $bxfeat = "http://www.bioxml.org/dtds/current/feature.dtd"; | |
573 | |
574 if ($self->_export_subfeatures() && $self->_group_subfeatures()) { | |
575 $feature_set_id = $self->{'id_counter'}; $self->{'id_counter'}++; | |
576 $writer->startTag([$namespace, 'feature_set'], | |
577 [$namespace, 'id'] => $feature_set_id); | |
578 foreach my $feature (@features) { | |
579 $self->__draw_feature($writer, $feature, $seq, $parent , 0); | |
580 } | |
581 $writer->endTag([$namespace, 'feature_set']); | |
582 foreach my $feature (@features) { | |
583 foreach my $subset ($self->_subfeature_types()) { | |
584 if (my @subfeatures = eval ( '$feature->' . $subset . '()' )) { | |
585 my @id = $feature->each_tag_value('id'); | |
586 $self->__draw_feature_set($writer, $seq, $namespace, $id[0], @subfeatures); | |
587 } | |
588 } | |
589 } | |
590 | |
591 } else { | |
592 $feature_set_id = $self->{'id_counter'}; $self->{'id_counter'}++; | |
593 $writer->startTag([$namespace, 'feature_set'], | |
594 [$namespace, 'id'] => $feature_set_id); | |
595 foreach my $feature (@features) { | |
596 $self->__draw_feature($writer, $feature, $seq, "" , $self->_export_subfeatures()); | |
597 } | |
598 $writer->endTag([$namespace, 'feature_set']); | |
599 } | |
600 } | |
601 | |
602 | |
603 sub __draw_feature { | |
604 my ($self, $writer, $feature, $seq, $parent, $recursive) = @_; | |
605 my ($subfeature, $subset, @subfeatures, $score, $score_val, $score_no); | |
606 my $bxfeat = "http://www.bioxml.org/dtds/current/feature.dtd"; | |
607 | |
608 if (!$feature->has_tag('id')) { | |
609 $feature->add_tag_value('id', $self->{'id_counter'}); | |
610 $self->{'id_counter'}++; | |
611 } | |
612 | |
613 my @id = $feature->each_tag_value('id'); | |
614 if ($parent) { | |
615 $writer->startTag([$bxfeat, 'feature'], | |
616 [$bxfeat, 'id'] => $id[0] | |
617 ); | |
618 } else { | |
619 $writer->startTag([$bxfeat, 'feature'], | |
620 [$bxfeat, 'id'] => $id[0], | |
621 [$bxfeat, 'parent'] => $parent | |
622 ); | |
623 } | |
624 $writer->startTag([$bxfeat, 'type']); | |
625 $writer->characters($feature->primary_tag()); | |
626 $writer->endTag([$bxfeat, 'type']); | |
627 foreach $score ($feature->all_tags()) { | |
628 next if ($score eq 'id'); | |
629 $writer->startTag([$bxfeat, 'score'], | |
630 [$bxfeat, 'type'] => $score | |
631 ); | |
632 $score_no = 0; | |
633 foreach $score_val ($feature->each_tag_value($score)) { | |
634 next unless defined $score_val; | |
635 $writer->characters(' ') if ($score_no > 0); | |
636 $writer->characters($score_val); | |
637 $score_no++; | |
638 } | |
639 $writer->endTag([$bxfeat, 'score']); | |
640 } | |
641 | |
642 $writer->startTag([$bxfeat, 'seq_relationship'], | |
643 [$bxfeat, 'seq'] => $seq->display_id, | |
644 [$bxfeat, 'type'] => 'query' | |
645 ); | |
646 | |
647 $writer->startTag([$bxfeat, 'span']); | |
648 $writer->startTag([$bxfeat, 'start']); | |
649 $writer->characters($feature->start()); | |
650 $writer->endTag([$bxfeat, 'start']); | |
651 $writer->startTag([$bxfeat, 'end']); | |
652 $writer->characters($feature->end()); | |
653 $writer->endTag([$bxfeat, 'end']); | |
654 $writer->endTag([$bxfeat, 'span']); | |
655 $writer->endTag([$bxfeat, 'seq_relationship']); | |
656 $writer->endTag([$bxfeat, 'feature']); | |
657 | |
658 #proces subseqfeature's, exons, introns, promotors, whatever... | |
659 if ($recursive) { | |
660 foreach $subset ($self->_subfeature_types()) { | |
661 #determine if it exists | |
662 if (@subfeatures = eval ( '$feature->' . $subset . '()' )) { | |
663 foreach $subfeature (@subfeatures) { | |
664 $self->__draw_feature ($writer, $subfeature, $seq, $id[0], 1); | |
665 } | |
666 } | |
667 } | |
668 } | |
669 } | |
670 | |
671 1; | |
672 |