changes all issue tracking in preparation for switch to github issues
[bioperl-live.git] / Bio / TreeIO / TreeEventBuilder.pm
blob7a509034f12a432d115c35472266669a8f66f36c
2 # BioPerl module for Bio::TreeIO::TreeEventBuilder
4 # Please direct questions and support issues to <bioperl-l@bioperl.org>
6 # Cared for by Jason Stajich <jason@bioperl.org>
8 # Copyright Jason Stajich
10 # You may distribute this module under the same terms as perl itself
12 # POD documentation - main docs before the code
14 =head1 NAME
16 Bio::TreeIO::TreeEventBuilder - Build Bio::Tree::Tree's and
17 Bio::Tree::Node's from Events
19 =head1 SYNOPSIS
21 # internal use only
23 =head1 DESCRIPTION
25 This object will take events and build a Bio::Tree::TreeI compliant
26 object makde up of Bio::Tree::NodeI objects.
28 =head1 FEEDBACK
30 =head2 Mailing Lists
32 User feedback is an integral part of the evolution of this and other
33 Bioperl modules. Send your comments and suggestions preferably to
34 the Bioperl mailing list. Your participation is much appreciated.
36 bioperl-l@bioperl.org - General discussion
37 http://bioperl.org/wiki/Mailing_lists - About the mailing lists
39 =head2 Support
41 Please direct usage questions or support issues to the mailing list:
43 I<bioperl-l@bioperl.org>
45 rather than to the module maintainer directly. Many experienced and
46 reponsive experts will be able look at the problem and quickly
47 address it. Please include a thorough description of the problem
48 with code and data examples if at all possible.
50 =head2 Reporting Bugs
52 Report bugs to the Bioperl bug tracking system to help us keep track
53 of the bugs and their resolution. Bug reports can be submitted via the
54 web:
56 https://github.com/bioperl/bioperl-live/issues
58 =head1 AUTHOR - Jason Stajich
60 Email jason-at-bioperl.org
62 =head1 APPENDIX
64 The rest of the documentation details each of the object methods.
65 Internal methods are usually preceded with a _
67 =cut
70 # Let the code begin...
73 package Bio::TreeIO::TreeEventBuilder;
74 use strict;
76 use Bio::Tree::Tree;
77 use Bio::Tree::Node;
79 use base qw(Bio::Root::Root Bio::Event::EventHandlerI);
81 =head2 new
83 Title : new
84 Usage : my $obj = Bio::TreeIO::TreeEventBuilder->new();
85 Function: Builds a new Bio::TreeIO::TreeEventBuilder object
86 Returns : Bio::TreeIO::TreeEventBuilder
87 Args :
90 =cut
92 sub new {
93 my($class,@args) = @_;
95 my $self = $class->SUPER::new(@args);
96 my ($treetype, $nodetype) = $self->_rearrange([qw(TREETYPE
97 NODETYPE)], @args);
98 $treetype ||= 'Bio::Tree::Tree';
99 $nodetype ||= 'Bio::Tree::Node';
101 eval {
102 $self->_load_module($treetype);
103 $self->_load_module($nodetype);
106 if( $@ ) {
107 $self->throw("Could not load module $treetype or $nodetype. \n$@\n")
109 $self->treetype($treetype);
110 $self->nodetype($nodetype);
111 $self->{'_treelevel'} = 0;
112 return $self;
115 =head2 treetype
117 Title : treetype
118 Usage : $obj->treetype($newval)
119 Function:
120 Returns : value of treetype
121 Args : newvalue (optional)
124 =cut
126 sub treetype{
127 my ($self,$value) = @_;
128 if( defined $value) {
129 $self->{'treetype'} = $value;
131 return $self->{'treetype'};
134 =head2 nodetype
136 Title : nodetype
137 Usage : $obj->nodetype($newval)
138 Function:
139 Returns : value of nodetype
140 Args : newvalue (optional)
143 =cut
145 sub nodetype{
146 my ($self,$value) = @_;
147 if( defined $value) {
148 $self->{'nodetype'} = $value;
150 return $self->{'nodetype'};
154 =head2 SAX methods
156 =cut
158 =head2 start_document
160 Title : start_document
161 Usage : $handler->start_document
162 Function: Begins a Tree event cycle
163 Returns : none
164 Args : none
166 =cut
168 sub start_document {
169 my ($self) = @_;
170 $self->{'_lastitem'} = {};
171 $self->{'_currentitems'} = [];
172 $self->{'_currentnodes'} = [];
173 return;
176 =head2 end_document
178 Title : end_document
179 Usage : my @trees = $parser->end_document
180 Function: Finishes a Phylogeny cycle
181 Returns : An array Bio::Tree::TreeI
182 Args : none
184 =cut
186 sub end_document {
187 my ($self,$label) = @_;
189 my ($root) = @{$self->{'_currentnodes'}};
191 $self->debug("Root node is " . $root->to_string()."\n");
192 if( $self->verbose > 0 ) {
193 foreach my $node ( $root->get_Descendents ) {
194 $self->debug("node is ". $node->to_string(). "\n");
197 my $tree = $self->treetype->new(-verbose => $self->verbose,
198 -root => $root);
199 return $tree;
202 =head2 start_element
204 Title : start_element
205 Usage :
206 Function:
207 Example :
208 Returns :
209 Args : $data => hashref with key 'Name'
211 =cut
213 sub start_element{
214 my ($self,$data) =@_;
215 $self->{'_lastitem'}->{$data->{'Name'}}++;
217 $self->debug("starting element: $data->{Name}\n");
218 push @{$self->{'_lastitem'}->{'current'}},$data->{'Name'};
220 my %data;
222 if( $data->{'Name'} eq 'node' ) {
223 push @{$self->{'_currentitems'}}, \%data;
224 $self->{'_treelevel'}++;
225 } elsif ( $data->{Name} eq 'tree' ) {
229 =head2 end_element
231 Title : end_element
232 Usage :
233 Function:
234 Returns : none
235 Args : $data => hashref with key 'Name'
237 =cut
239 sub end_element{
240 my ($self,$data) = @_;
242 $self->debug("end of element: $data->{Name}\n");
243 # this is the stack where we push/pop items from it
244 my $curcount = scalar @{$self->{'_currentnodes'}};
245 my $level = $self->{'_treelevel'};
246 my $levelct = $self->{'_nodect'}->[$self->{'_treelevel'}+1] || 0;
248 if( $data->{'Name'} eq 'node' ) {
249 my $tnode;
250 my $node = pop @{$self->{'_currentitems'}};
252 $tnode = $self->nodetype->new( -verbose => $self->verbose,
253 %{$node});
254 $self->debug( "new node will be ".$tnode->to_string."\n");
255 if ( !$node->{'-leaf'} && $levelct > 0) {
256 $self->debug(join(',', map { $_->to_string }
257 @{$self->{'_currentnodes'}}). "\n");
258 $self->throw("something wrong with event construction treelevel ".
259 "$level is recorded as having $levelct nodes ".
260 "but current nodes at this level is $curcount\n")
261 if( $levelct > $curcount);
262 for ( splice( @{$self->{'_currentnodes'}}, - $levelct)) {
263 $self->debug("adding desc: " . $_->to_string . "\n");
264 $tnode->add_Descendent($_);
266 $self->{'_nodect'}->[$self->{'_treelevel'}+1] = 0;
268 push @{$self->{'_currentnodes'}}, $tnode;
269 $self->{'_nodect'}->[$self->{'_treelevel'}]++;
271 $curcount = scalar @{$self->{'_currentnodes'}};
272 $self->debug ("added node: count is now $curcount, treelevel: $level, nodect: $levelct\n");
274 $self->{'_treelevel'}--;
275 } elsif( $data->{'Name'} eq 'tree' ) {
276 $self->debug("end of tree: nodes in stack is $curcount\n");
279 $self->{'_lastitem'}->{ $data->{'Name'} }--;
280 pop @{$self->{'_lastitem'}->{'current'}};
284 =head2 in_element
286 Title : in_element
287 Usage :
288 Function:
289 Example :
290 Returns :
291 Args :
294 =cut
296 sub in_element{
297 my ($self,$e) = @_;
299 return 0 if ! defined $self->{'_lastitem'} ||
300 ! defined $self->{'_lastitem'}->{'current'}->[-1];
301 return ($e eq $self->{'_lastitem'}->{'current'}->[-1]);
305 =head2 within_element
307 Title : within_element
308 Usage :
309 Function:
310 Example :
311 Returns :
312 Args :
315 =cut
317 sub within_element{
318 my ($self,$e) = @_;
319 return $self->{'_lastitem'}->{$e};
322 =head2 characters
324 Title : characters
325 Usage : $handler->characters($text);
326 Function: Processes characters
327 Returns : none
328 Args : text string
331 =cut
333 sub characters{
334 my ($self,$ch) = @_;
335 if( $self->within_element('node') ) {
336 my $hash = pop @{$self->{'_currentitems'}};
337 if( $self->in_element('bootstrap') ) {
338 # leading/trailing Whitespace-B-Gone
339 $ch =~ s/^\s+//; $ch =~ s/\s+$//;
340 $hash->{'-bootstrap'} = $ch;
341 } elsif( $self->in_element('branch_length') ) {
342 # leading/trailing Whitespace-B-Gone
343 $ch =~ s/^\s+//; $ch =~ s/\s+$//;
344 $hash->{'-branch_length'} = $ch;
345 } elsif( $self->in_element('id') ) {
346 $hash->{'-id'} = $ch;
347 } elsif( $self->in_element('description') ) {
348 $hash->{'-desc'} = $ch;
349 } elsif ( $self->in_element('tag_name') ) {
350 $hash->{'-NHXtagname'} = $ch;
351 } elsif ( $self->in_element('tag_value') ) {
352 $hash->{'-nhx'}->{$hash->{'-NHXtagname'}} = $ch;
353 delete $hash->{'-NHXtagname'};
354 } elsif( $self->in_element('leaf') ) {
355 $hash->{'-leaf'} = $ch;
357 push @{$self->{'_currentitems'}}, $hash;
359 $self->debug("chars: $ch\n");