sub
_initialize {
my
(
$self
,
%args
) =
@_
;
$args
{-nodetype} ||=
'Bio::Tree::NodeNHX'
;
$self
->SUPER::_initialize(
%args
);
}
sub
next_tree{
my
(
$self
) =
@_
;
local
$/ =
";\n"
;
return
unless
$_
=
$self
->_readline;
s/\s+//g;
$self
->debug(
"entry is $_\n"
);
my
$chars
=
''
;
$self
->_eventHandler->start_document;
my
(
$prev_event
,
$lastevent
,
$last_leaf_event
) = (
''
,
''
,
''
);
my
@ch
=
split
(//,
$_
);
foreach
my
$ch
(
@ch
) {
if
(
$ch
eq
';'
) {
$self
->_eventHandler->in_element(
'node'
) &&
$self
->_eventHandler->end_element( {
'Name'
=>
'node'
});
return
$self
->_eventHandler->end_document;
}
elsif
(
$ch
eq
'['
) {
if
(
length
$chars
) {
if
(
$lastevent
eq
':'
) {
$self
->_eventHandler->start_element( {
Name
=>
'branch_length'
} );
$self
->_eventHandler->characters(
$chars
);
$self
->_eventHandler->end_element( {
Name
=>
'branch_length'
});
$lastevent
=
$prev_event
;
}
else
{
$self
->debug(
"id with no branchlength is $chars\n"
);
$self
->_eventHandler->start_element( {
'Name'
=>
'node'
} );
$self
->_eventHandler->start_element( {
'Name'
=>
'id'
} );
$self
->_eventHandler->characters(
$chars
);
$self
->_eventHandler->end_element( {
'Name'
=>
'id'
} );
}
}
else
{
$self
->_eventHandler->start_element( {
Name
=>
'node'
} );
}
my
$leafstatus
= (
$last_leaf_event
ne
')'
) ? 1 : 0;
$self
->_eventHandler->start_element({
'Name'
=>
'leaf'
});
$self
->_eventHandler->characters(
$leafstatus
);
$self
->_eventHandler->end_element({
'Name'
=>
'leaf'
});
$chars
=
''
;
$self
->_eventHandler->start_element( {
Name
=>
'nhx_tag'
});
}
elsif
(
$ch
eq
'('
) {
$chars
=
''
;
$self
->_eventHandler->start_element( {
'Name'
=>
'tree'
} );
}
elsif
(
$ch
eq
')'
) {
if
(
length
$chars
) {
if
(
$lastevent
eq
':'
) {
unless
(
$self
->_eventHandler->within_element(
'nhx_tag'
)) {
$self
->_eventHandler->start_element( {
'Name'
=>
'branch_length'
});
$self
->_eventHandler->characters(
$chars
);
$self
->_eventHandler->end_element( {
'Name'
=>
'branch_length'
});
}
else
{
$self
->throw(
"malformed input; end of node ) before ] found"
);
}
}
else
{
$self
->debug(
"id with no branchlength is '$chars'\n"
);
$self
->_eventHandler->start_element( {
'Name'
=>
'node'
} );
$self
->_eventHandler->start_element( {
'Name'
=>
'id'
} );
$self
->_eventHandler->characters(
$chars
);
$self
->_eventHandler->end_element( {
'Name'
=>
'id'
} );
}
}
elsif
(
$lastevent
ne
']'
) {
$self
->_eventHandler->start_element( {
'Name'
=>
'node'
} );
}
my
$leafstatus
= (
$last_leaf_event
ne
')'
) ? 1 : 0;
$self
->_eventHandler->start_element({
'Name'
=>
'leaf'
});
$self
->_eventHandler->characters(
$leafstatus
);
$self
->_eventHandler->end_element({
'Name'
=>
'leaf'
});
$self
->_eventHandler->end_element( {
'Name'
=>
'node'
} );
$self
->_eventHandler->end_element( {
'Name'
=>
'tree'
} );
$chars
=
''
;
$last_leaf_event
=
$ch
;
}
elsif
(
$ch
eq
','
) {
if
(
length
$chars
) {
if
(
$lastevent
eq
':'
) {
$self
->_eventHandler->start_element( {
'Name'
=>
'branch_length'
});
$self
->_eventHandler->characters(
$chars
);
$self
->_eventHandler->end_element( {
'Name'
=>
'branch_length'
});
$lastevent
=
$prev_event
;
}
else
{
$self
->debug(
"id with no branchlength is $chars\n"
);
$self
->_eventHandler->start_element( {
'Name'
=>
'node'
} );
$self
->_eventHandler->start_element( {
'Name'
=>
'id'
} );
$self
->_eventHandler->characters(
$chars
);
$self
->_eventHandler->end_element( {
'Name'
=>
'id'
} );
}
}
elsif
(
$lastevent
ne
']'
) {
$self
->_eventHandler->start_element( {
'Name'
=>
'node'
} );
}
$self
->_eventHandler->end_element( {
'Name'
=>
'node'
} );
$chars
=
''
;
$last_leaf_event
=
$ch
;
}
elsif
(
$ch
eq
':'
) {
if
(
$self
->_eventHandler->within_element(
'nhx_tag'
)) {
if
(
$lastevent
eq
'='
) {
$self
->_eventHandler->start_element( {
Name
=>
'tag_value'
} );
$self
->_eventHandler->characters(
$chars
);
$self
->_eventHandler->end_element( {
Name
=>
'tag_value'
} );
$chars
=
''
;
}
else
{
if
(
$chars
eq
'&&NHX'
) {
$chars
=
''
;
}
else
{
$self
->throw(
"Unrecognized, non \&\&NHX string: >>$chars<<"
);
}
}
}
elsif
(
$lastevent
ne
']'
) {
$self
->debug(
"id with a branchlength coming is $chars\n"
);
$self
->_eventHandler->start_element( {
'Name'
=>
'node'
} );
$self
->_eventHandler->start_element( {
'Name'
=>
'id'
} );
$self
->_eventHandler->characters(
$chars
);
$self
->_eventHandler->end_element( {
'Name'
=>
'id'
} );
$chars
=
''
;
}
}
elsif
(
$ch
eq
'='
) {
if
(
$self
->_eventHandler->within_element(
'nhx_tag'
)) {
$self
->_eventHandler->start_element( {
Name
=>
'tag_name'
} );
$self
->_eventHandler->characters(
$chars
);
$self
->_eventHandler->end_element( {
Name
=>
'tag_name'
} );
$chars
=
''
;
}
else
{
$chars
.=
$ch
;
}
}
elsif
(
$ch
eq
']'
) {
if
(
$self
->_eventHandler->within_element(
'nhx_tag'
) &&
$lastevent
eq
'='
) {
$self
->_eventHandler->start_element( {
Name
=>
'tag_value'
} );
$self
->_eventHandler->characters(
$chars
);
$self
->_eventHandler->end_element( {
Name
=>
'tag_value'
} );
$chars
=
''
;
$self
->_eventHandler->end_element( {
Name
=>
'nhx_tag'
} );
}
else
{
$chars
.=
$ch
;
next
;
}
}
else
{
$chars
.=
$ch
;
next
;
}
$prev_event
=
$lastevent
;
$lastevent
=
$ch
;
}
return
;
}
sub
write_tree{
my
(
$self
,
@trees
) =
@_
;
my
$nl
=
$self
->newline_each_node;
foreach
my
$tree
(
@trees
) {
my
@data
= _write_tree_Helper(
$tree
->get_root_node,
$nl
);
if
(
$data
[-1] =~ s/\)$// ) {
$data
[0] =~ s/^\(//;
}
if
(
$nl
) {
chomp
(
$data
[-1]);
$self
->_print(
join
(
",\n"
,
@data
),
";\n"
);
}
else
{
$self
->_print(
join
(
','
,
@data
),
";\n"
);
}
}
$self
->flush
if
$self
->_flush_on_write &&
defined
$self
->_fh;
return
;
}
sub
_write_tree_Helper {
my
(
$node
,
$nl
) =
@_
;
return
()
unless
defined
$node
;
$node
=
bless
$node
,
'Bio::Tree::NodeNHX'
;
my
@data
;
foreach
my
$n
(
$node
->each_Descendent() ) {
push
@data
, _write_tree_Helper(
$n
,
$nl
);
}
if
(
@data
> 1 ) {
if
(
$nl
) {
$data
[0] =
"(\n"
.
$data
[0];
$data
[-1] .=
")\n"
;
}
else
{
$data
[0] =
"("
.
$data
[0];
$data
[-1] .=
")"
;
}
my
$id
=
$node
->id;
$data
[-1] .=
$id
if
(
defined
$id
);
my
$blen
=
$node
->branch_length;
$data
[-1] .=
":"
.
$blen
if
$blen
;
my
@tags
=
$node
->get_all_tags;
if
(
$node
->ancestor ||
@tags
) {
$data
[-1] .=
'['
.
join
(
":"
,
"&&NHX"
,
map
{
"$_="
.
join
(
','
,
$node
->get_tag_values(
$_
)) }
@tags
) .
']'
;
}
else
{
if
(
$nl
) {
$data
[0] =
"(\n"
.
$data
[0];
$data
[-1] .=
")\n"
;
}
else
{
$data
[0] =
"("
.
$data
[0];
$data
[-1] .=
")"
;
}
}
}
else
{
push
@data
,
$node
->to_string;
}
return
@data
;
}
1;