line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# $Id: TagTree.pm 11693 2007-09-17 20:54:04Z cjfields $ |
2
|
|
|
|
|
|
|
# |
3
|
|
|
|
|
|
|
# BioPerl module for Bio::Annotation::TagTree |
4
|
|
|
|
|
|
|
# |
5
|
|
|
|
|
|
|
# Cared for Chris Fields |
6
|
|
|
|
|
|
|
# |
7
|
|
|
|
|
|
|
# You may distribute this module under the same terms as perl itself. |
8
|
|
|
|
|
|
|
# Refer to the Perl Artistic License (see the license accompanying this |
9
|
|
|
|
|
|
|
# software package, or see http://www.perl.com/language/misc/Artistic.html) |
10
|
|
|
|
|
|
|
# for the terms under which you may use, modify, and redistribute this module. |
11
|
|
|
|
|
|
|
# |
12
|
|
|
|
|
|
|
# THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED |
13
|
|
|
|
|
|
|
# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
14
|
|
|
|
|
|
|
# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
15
|
|
|
|
|
|
|
# |
16
|
|
|
|
|
|
|
# POD documentation - main docs before the code |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=head1 NAME |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
Bio::Annotation::TagTree - AnnotationI with tree-like hierarchal key-value |
21
|
|
|
|
|
|
|
relationships ('structured tags') that can be represented as simple text. |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=head1 SYNOPSIS |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
use Bio::Annotation::TagTree; |
26
|
|
|
|
|
|
|
use Bio::Annotation::Collection; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
my $col = Bio::Annotation::Collection->new(); |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# data structure can be an array reference with a data structure |
31
|
|
|
|
|
|
|
# corresponding to that defined by Data::Stag: |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
my $sv = Bio::Annotation::TagTree->new(-tagname => 'mytag1', |
34
|
|
|
|
|
|
|
-value => $data_structure); |
35
|
|
|
|
|
|
|
$col->add_Annotation($sv); |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
# regular text passed is parsed based on the tagformat(). |
38
|
|
|
|
|
|
|
my $sv2 = Bio::Annotation::TagTree->new(-tagname => 'mytag2', |
39
|
|
|
|
|
|
|
-tagformat => 'xml', |
40
|
|
|
|
|
|
|
-value => $xmltext); |
41
|
|
|
|
|
|
|
$col->add_Annotation($sv2); |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
=head1 DESCRIPTION |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
This takes tagged data values and stores them in a hierarchal structured |
46
|
|
|
|
|
|
|
element-value hierarchy (complements of Chris Mungall's Data::Stag module). Data |
47
|
|
|
|
|
|
|
can then be represented as text using a variety of output formats (indention, |
48
|
|
|
|
|
|
|
itext, xml, spxr). Furthermore, the data structure can be queried using various |
49
|
|
|
|
|
|
|
means. See L for details. |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
Data passed in using value() or the '-value' parameter upon instantiation |
52
|
|
|
|
|
|
|
can either be: |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
1) an array reference corresponding to the data structure for Data::Stag; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
2) a text string in 'xml', 'itext', 'spxr', or 'indent' format. The default |
57
|
|
|
|
|
|
|
format is 'xml'; this can be changed using tagformat() prior to using value() or |
58
|
|
|
|
|
|
|
by passing in the proper format using '-tagformat' upon instantiation; |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
3) another Bio::Annotation::TagTree or Data::Stag node instance. In both cases |
61
|
|
|
|
|
|
|
a deep copy (duplicate) of the instance is generated. |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
Beyond checking for an array reference no format guessing occurs (so, for |
64
|
|
|
|
|
|
|
roundtrip tests ensure that the IO formats correspond). For now, we recommend |
65
|
|
|
|
|
|
|
when using text input to set tagformat() to one of these formats prior to data |
66
|
|
|
|
|
|
|
loading to ensure the proper Data::Stag parser is selected. After data loading, |
67
|
|
|
|
|
|
|
the tagformat() can be changed to change the text string format returned by |
68
|
|
|
|
|
|
|
value(). (this may be rectified in the future) |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
This Annotation type is fully BioSQL compatible and could be considered a |
71
|
|
|
|
|
|
|
temporary replacement for nested Bio::Annotation::Collections, at least until |
72
|
|
|
|
|
|
|
BioSQL and bioperl-db can support nested annotation collections. |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=head1 FEEDBACK |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=head2 Mailing Lists |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
User feedback is an integral part of the evolution of this and other |
79
|
|
|
|
|
|
|
Bioperl modules. Send your comments and suggestions preferably to one |
80
|
|
|
|
|
|
|
of the Bioperl mailing lists. Your participation is much appreciated. |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
bioperl-l@bioperl.org - General discussion |
83
|
|
|
|
|
|
|
http://bioperl.org/wiki/Mailing_lists - About the mailing lists |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
=head2 Support |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
Please direct usage questions or support issues to the mailing list: |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
I |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
rather than to the module maintainer directly. Many experienced and |
92
|
|
|
|
|
|
|
reponsive experts will be able look at the problem and quickly |
93
|
|
|
|
|
|
|
address it. Please include a thorough description of the problem |
94
|
|
|
|
|
|
|
with code and data examples if at all possible. |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
=head2 Reporting Bugs |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
Report bugs to the Bioperl bug tracking system to help us keep track |
99
|
|
|
|
|
|
|
the bugs and their resolution. Bug reports can be submitted via |
100
|
|
|
|
|
|
|
or the web: |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
https://github.com/bioperl/bioperl-live/issues |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=head1 AUTHOR |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
Chris Fields |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=head1 APPENDIX |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
The rest of the documentation details each of the object methods. Internal |
111
|
|
|
|
|
|
|
methods are usually preceded with a _ |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
=cut |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
# Let the code begin... |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
package Bio::Annotation::TagTree; |
118
|
8
|
|
|
8
|
|
717
|
use strict; |
|
8
|
|
|
|
|
16
|
|
|
8
|
|
|
|
|
233
|
|
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
# Object preamble - inherits from Bio::Root::Root |
121
|
|
|
|
|
|
|
|
122
|
8
|
|
|
8
|
|
35
|
use base qw(Bio::Annotation::SimpleValue); |
|
8
|
|
|
|
|
14
|
|
|
8
|
|
|
|
|
637
|
|
123
|
8
|
|
|
8
|
|
44
|
use Data::Stag; |
|
8
|
|
|
|
|
62
|
|
|
8
|
|
|
|
|
9201
|
|
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=head2 new |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
Title : new |
128
|
|
|
|
|
|
|
Usage : my $sv = Bio::Annotation::TagTree->new(); |
129
|
|
|
|
|
|
|
Function: Instantiate a new TagTree object |
130
|
|
|
|
|
|
|
Returns : Bio::Annotation::TagTree object |
131
|
|
|
|
|
|
|
Args : -value => $value to initialize the object data field [optional] |
132
|
|
|
|
|
|
|
-tagname => $tag to initialize the tagname [optional] |
133
|
|
|
|
|
|
|
-tagformat => format for output [optional] |
134
|
|
|
|
|
|
|
(types 'xml', 'itext', 'sxpr', 'indent', default = 'itext') |
135
|
|
|
|
|
|
|
-node => Data::Stag node or Bio::Annotation::TagTree instance |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
=cut |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
sub new { |
140
|
60
|
|
|
60
|
1
|
4423
|
my ( $class, @args ) = @_; |
141
|
60
|
|
|
|
|
338
|
my $self = $class->SUPER::new(); |
142
|
60
|
|
|
|
|
345
|
my ( $node, $value, $tag, $format, $verbose ) = $self->_rearrange( |
143
|
|
|
|
|
|
|
[ |
144
|
|
|
|
|
|
|
qw( |
145
|
|
|
|
|
|
|
NODE |
146
|
|
|
|
|
|
|
VALUE |
147
|
|
|
|
|
|
|
TAGNAME |
148
|
|
|
|
|
|
|
TAGFORMAT |
149
|
|
|
|
|
|
|
VERBOSE) |
150
|
|
|
|
|
|
|
], |
151
|
|
|
|
|
|
|
@args |
152
|
|
|
|
|
|
|
); |
153
|
60
|
50
|
33
|
|
|
317
|
$self->throw("Cant use both node and value; mutually exclusive") |
154
|
|
|
|
|
|
|
if defined $node && defined $value; |
155
|
60
|
100
|
|
|
|
335
|
defined $tag && $self->tagname($tag); |
156
|
60
|
|
50
|
|
|
328
|
$format ||= 'itext'; |
157
|
60
|
|
|
|
|
228
|
$self->tagformat($format); |
158
|
60
|
100
|
|
|
|
289
|
defined $value && $self->value($value); |
159
|
60
|
50
|
|
|
|
70554
|
defined $node && $self->node($node); |
160
|
60
|
100
|
|
|
|
243
|
defined $verbose && $self->verbose($verbose); |
161
|
60
|
|
|
|
|
267
|
return $self; |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
=head1 AnnotationI implementing functions |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
=cut |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=head2 as_text |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
Title : as_text |
171
|
|
|
|
|
|
|
Usage : my $text = $obj->as_text |
172
|
|
|
|
|
|
|
Function: return the string "Value: $v" where $v is the value |
173
|
|
|
|
|
|
|
Returns : string |
174
|
|
|
|
|
|
|
Args : none |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
=cut |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
sub as_text { |
179
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
180
|
0
|
|
|
|
|
0
|
return "TagTree: " . $self->value; |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
=head2 display_text |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
Title : display_text |
186
|
|
|
|
|
|
|
Usage : my $str = $ann->display_text(); |
187
|
|
|
|
|
|
|
Function: returns a string. Unlike as_text(), this method returns a string |
188
|
|
|
|
|
|
|
formatted as would be expected for the specific implementation. |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
One can pass a callback as an argument which allows custom text |
191
|
|
|
|
|
|
|
generation; the callback is passed the current instance and any text |
192
|
|
|
|
|
|
|
returned |
193
|
|
|
|
|
|
|
Example : |
194
|
|
|
|
|
|
|
Returns : a string |
195
|
|
|
|
|
|
|
Args : [optional] callback |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
=cut |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
{ |
200
|
|
|
|
|
|
|
my $DEFAULT_CB = sub { $_[0]->value || '' }; |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
sub display_text { |
203
|
0
|
|
|
0
|
1
|
0
|
my ( $self, $cb ) = @_; |
204
|
0
|
|
0
|
|
|
0
|
$cb ||= $DEFAULT_CB; |
205
|
0
|
0
|
|
|
|
0
|
$self->throw("Callback must be a code reference") if ref $cb ne 'CODE'; |
206
|
0
|
|
|
|
|
0
|
return $cb->($self); |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=head2 hash_tree |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
Title : hash_tree |
214
|
|
|
|
|
|
|
Usage : my $hashtree = $value->hash_tree |
215
|
|
|
|
|
|
|
Function: For supporting the AnnotationI interface just returns the value |
216
|
|
|
|
|
|
|
as a hashref with the key 'value' pointing to the value |
217
|
|
|
|
|
|
|
Maybe reimplement using Data::Stag::hash()? |
218
|
|
|
|
|
|
|
Returns : hashrf |
219
|
|
|
|
|
|
|
Args : none |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=cut |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
sub hash_tree { |
224
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
225
|
0
|
|
|
|
|
0
|
my $h = {}; |
226
|
0
|
|
|
|
|
0
|
$h->{'value'} = $self->value; |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=head2 tagname |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
Title : tagname |
232
|
|
|
|
|
|
|
Usage : $obj->tagname($newval) |
233
|
|
|
|
|
|
|
Function: Get/set the tagname for this annotation value. |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
Setting this is optional. If set, it obviates the need to provide |
236
|
|
|
|
|
|
|
a tag to AnnotationCollection when adding this object. |
237
|
|
|
|
|
|
|
Example : |
238
|
|
|
|
|
|
|
Returns : value of tagname (a scalar) |
239
|
|
|
|
|
|
|
Args : new value (a scalar, optional) |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=cut |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
sub tagname { |
244
|
78
|
|
|
78
|
1
|
223
|
my ( $self, $value ) = @_; |
245
|
78
|
100
|
|
|
|
234
|
if ( defined $value ) { |
246
|
58
|
|
|
|
|
203
|
$self->{'tagname'} = $value; |
247
|
|
|
|
|
|
|
} |
248
|
78
|
|
|
|
|
208
|
return $self->{'tagname'}; |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
=head1 Specific accessors for TagTree |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=cut |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
=head2 value |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
Title : value |
258
|
|
|
|
|
|
|
Usage : $obj->value($newval) |
259
|
|
|
|
|
|
|
Function: Get/set the value for this annotation. |
260
|
|
|
|
|
|
|
Returns : value of value |
261
|
|
|
|
|
|
|
Args : newvalue (optional) |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
=cut |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
sub value { |
266
|
81
|
|
|
81
|
1
|
9631
|
my ( $self, $value ) = @_; |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
# set mode? This resets the entire tagged database |
269
|
81
|
|
|
|
|
198
|
my $format = $self->tagformat; |
270
|
81
|
100
|
|
|
|
491
|
if ($value) { |
271
|
58
|
100
|
|
|
|
176
|
if ( ref $value ) { |
272
|
57
|
100
|
|
|
|
206
|
if ( ref $value eq 'ARRAY' ) { |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
# note the tagname() is not used here; it is only used for |
275
|
|
|
|
|
|
|
# storing this AnnotationI in the annotation collection |
276
|
53
|
|
|
|
|
113
|
eval { $self->{db} = Data::Stag->nodify($value) }; |
|
53
|
|
|
|
|
817
|
|
277
|
|
|
|
|
|
|
} |
278
|
|
|
|
|
|
|
else { |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
# assuming this is blessed; passing on to node() and copy |
281
|
4
|
|
|
|
|
7
|
$self->node( $value, 'copy' ); |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
else { |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
# not trying to guess here for now; we go by the tagformat() setting |
287
|
1
|
|
|
|
|
11
|
my $h = Data::Stag->getformathandler($format); |
288
|
1
|
|
|
|
|
175
|
eval { $self->{db} = Data::Stag->from( $format . 'str', $value ) }; |
|
1
|
|
|
|
|
9
|
|
289
|
|
|
|
|
|
|
} |
290
|
58
|
50
|
|
|
|
10112
|
$self->throw("Data::Stag error:\n$@") if $@; |
291
|
|
|
|
|
|
|
} |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
# get mode? |
294
|
|
|
|
|
|
|
# How do we return a data structure? |
295
|
|
|
|
|
|
|
# for now, we use the output (if there is a Data::Stag node present) |
296
|
|
|
|
|
|
|
# may need to run an eval {} to catch Data::Stag output errors |
297
|
81
|
|
|
|
|
498
|
$self->node->$format; |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
=head2 tagformat |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
Title : tagformat |
303
|
|
|
|
|
|
|
Usage : $obj->tagformat($newval) |
304
|
|
|
|
|
|
|
Function: Get/set the output tag format for this annotation. |
305
|
|
|
|
|
|
|
Returns : value of tagformat |
306
|
|
|
|
|
|
|
Args : newvalue (optional) - format for the data passed into value |
307
|
|
|
|
|
|
|
must be of values 'xml', 'indent', 'sxpr', 'itext', 'perl' |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
=cut |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
my %IS_VALID_FORMAT = map { $_ => 1 } qw(xml indent sxpr itext); |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
sub tagformat { |
314
|
144
|
|
|
144
|
1
|
11854
|
my ( $self, $value ) = @_; |
315
|
144
|
100
|
|
|
|
337
|
if ( defined $value ) { |
316
|
|
|
|
|
|
|
$self->throw( "$value is not a valid format; valid format types:\n" |
317
|
0
|
|
|
|
|
0
|
. join( ',', map { "'$_'" } keys %IS_VALID_FORMAT ) ) |
318
|
63
|
50
|
|
|
|
251
|
if !exists $IS_VALID_FORMAT{$value}; |
319
|
63
|
|
|
|
|
178
|
$self->{'tagformat'} = $value; |
320
|
|
|
|
|
|
|
} |
321
|
144
|
|
|
|
|
253
|
return $self->{'tagformat'}; |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
=head2 node |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
Title : node |
327
|
|
|
|
|
|
|
Usage : $obj->node() |
328
|
|
|
|
|
|
|
Function: Get/set the topmost Data::Stag node used for this annotation. |
329
|
|
|
|
|
|
|
Returns : Data::Stag node implementation |
330
|
|
|
|
|
|
|
(default is Data::Stag::StagImpl) |
331
|
|
|
|
|
|
|
Args : (optional) Data::Stag node implementation |
332
|
|
|
|
|
|
|
(optional)'copy' => flag to create a copy of the node |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
=cut |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
sub node { |
337
|
120
|
|
|
120
|
1
|
6736
|
my ( $self, $value, $copy ) = @_; |
338
|
120
|
100
|
66
|
|
|
411
|
if ( defined $value && ref $value ) { |
339
|
6
|
100
|
66
|
|
|
48
|
$self->{'db'} = |
|
|
50
|
33
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
340
|
|
|
|
|
|
|
$value->isa('Data::Stag::StagI') |
341
|
|
|
|
|
|
|
? ( $copy && $copy eq 'copy' ? $value->duplicate : $value ) |
342
|
|
|
|
|
|
|
: $value->isa('Bio::Annotation::TagTree') ? ( $copy |
343
|
|
|
|
|
|
|
&& $copy eq 'copy' ? $value->node->duplicate : $value->node ) |
344
|
|
|
|
|
|
|
: $self->throw( |
345
|
|
|
|
|
|
|
'Object must be Data::Stag::StagI or Bio::Annotation::TagTree'); |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
# lazily create Data::Stag instance if not present |
349
|
120
|
100
|
|
|
|
2310
|
if (!$self->{'db'}) { |
350
|
4
|
|
|
|
|
14
|
$self->{'db'} = Data::Stag->new(); |
351
|
|
|
|
|
|
|
} |
352
|
120
|
|
|
|
|
772
|
return $self->{'db'}; |
353
|
|
|
|
|
|
|
} |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
=head2 Data::Stag convenience methods |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
Because Data::Stag uses blessed arrays and the core Bioperl class uses blessed |
358
|
|
|
|
|
|
|
hashes, TagTree uses an internal instance of a Data::Stag node for data storage. |
359
|
|
|
|
|
|
|
Therefore the following methods actually delegate to the Data:::Stag internal |
360
|
|
|
|
|
|
|
instance. |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
For consistency (since one could recursively check child nodes), methods retain |
363
|
|
|
|
|
|
|
the same names as Data::Stag. Also, no 'magic' (AUTOLOAD'ed) methods are |
364
|
|
|
|
|
|
|
employed, simply b/c full-fledged Data::Stag functionality can be attained by |
365
|
|
|
|
|
|
|
grabbing the Data::Stag instance using node(). |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
=head2 element |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
Title : element |
370
|
|
|
|
|
|
|
Usage : |
371
|
|
|
|
|
|
|
Function: Returns the element name (key name) for this node |
372
|
|
|
|
|
|
|
Example : |
373
|
|
|
|
|
|
|
Returns : scalar |
374
|
|
|
|
|
|
|
Args : none |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
=cut |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
sub element { |
379
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
380
|
0
|
|
|
|
|
0
|
return $self->node->element; |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
=head2 data |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
Title : data |
386
|
|
|
|
|
|
|
Usage : |
387
|
|
|
|
|
|
|
Function: Returns the data structure (array ref) for this node |
388
|
|
|
|
|
|
|
Example : |
389
|
|
|
|
|
|
|
Returns : array ref |
390
|
|
|
|
|
|
|
Args : none |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
=cut |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
sub data { |
395
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
396
|
0
|
|
|
|
|
0
|
return $self->node->data; |
397
|
|
|
|
|
|
|
} |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
=head2 children |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
Title : children |
402
|
|
|
|
|
|
|
Usage : |
403
|
|
|
|
|
|
|
Function: Get the top-level array of Data::Stag nodes or (if the top level is |
404
|
|
|
|
|
|
|
a terminal node) a scalar value. |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
This is similar to StructuredValue's get_values() method, with the |
407
|
|
|
|
|
|
|
key difference being instead of array refs and scalars you get either |
408
|
|
|
|
|
|
|
Data::Stag nodes or the value for this particular node. |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
For consistency (since one could recursively check nodes), |
411
|
|
|
|
|
|
|
we use the same method name as Data::Stag children(). |
412
|
|
|
|
|
|
|
Example : |
413
|
|
|
|
|
|
|
Returns : an array |
414
|
|
|
|
|
|
|
Args : none |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
=cut |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
sub children { |
419
|
6
|
|
|
6
|
1
|
4234
|
my $self = shift; |
420
|
6
|
|
|
|
|
33
|
return $self->node->children; |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
=head2 subnodes |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
Title : subnodes |
426
|
|
|
|
|
|
|
Usage : |
427
|
|
|
|
|
|
|
Function: Get the top-level array of Data::Stag nodes. Unlike children(), |
428
|
|
|
|
|
|
|
this only returns an array of nodes (if this is a terminal node, |
429
|
|
|
|
|
|
|
no value is returned) |
430
|
|
|
|
|
|
|
Example : |
431
|
|
|
|
|
|
|
Returns : an array of nodes |
432
|
|
|
|
|
|
|
Args : none |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
=cut |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
sub subnodes { |
437
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
438
|
0
|
|
|
|
|
0
|
return $self->node->subnodes; |
439
|
|
|
|
|
|
|
} |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
=head2 get |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
Title : get |
444
|
|
|
|
|
|
|
Usage : |
445
|
|
|
|
|
|
|
Function: Returns the nodes or value for the named element or path |
446
|
|
|
|
|
|
|
Example : |
447
|
|
|
|
|
|
|
Returns : returns array of nodes or a scalar (if node is terminal) |
448
|
|
|
|
|
|
|
dependent on wantarray |
449
|
|
|
|
|
|
|
Args : none |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
=cut |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
sub get { |
454
|
0
|
|
|
0
|
1
|
0
|
my ( $self, @vals ) = @_; |
455
|
0
|
|
|
|
|
0
|
return $self->node->get(@vals); |
456
|
|
|
|
|
|
|
} |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
=head2 find |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
Title : find |
461
|
|
|
|
|
|
|
Usage : |
462
|
|
|
|
|
|
|
Function: Recursively searches for and returns the nodes or values for the |
463
|
|
|
|
|
|
|
named element or path |
464
|
|
|
|
|
|
|
Example : |
465
|
|
|
|
|
|
|
Returns : returns array of nodes or scalars (for terminal nodes) |
466
|
|
|
|
|
|
|
Args : none |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
=cut |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
sub find { |
471
|
0
|
|
|
0
|
1
|
0
|
my ( $self, @vals ) = @_; |
472
|
0
|
|
|
|
|
0
|
return $self->node->find(@vals); |
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
=head2 findnode |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
Title : findnode |
478
|
|
|
|
|
|
|
Usage : |
479
|
|
|
|
|
|
|
Function: Recursively searches for and returns a list of nodes |
480
|
|
|
|
|
|
|
of the given element path |
481
|
|
|
|
|
|
|
Example : |
482
|
|
|
|
|
|
|
Returns : returns array of nodes |
483
|
|
|
|
|
|
|
Args : none |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
=cut |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
sub findnode { |
488
|
6
|
|
|
6
|
1
|
2306
|
my ( $self, @vals ) = @_; |
489
|
6
|
|
|
|
|
27
|
return $self->node->findnode(@vals); |
490
|
|
|
|
|
|
|
} |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
=head2 findval |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
Title : findval |
495
|
|
|
|
|
|
|
Usage : |
496
|
|
|
|
|
|
|
Function: |
497
|
|
|
|
|
|
|
Example : |
498
|
|
|
|
|
|
|
Returns : returns array of nodes or values |
499
|
|
|
|
|
|
|
Args : none |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
=cut |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
sub findval { |
504
|
4
|
|
|
4
|
1
|
935
|
my ( $self, @vals ) = @_; |
505
|
4
|
|
|
|
|
17
|
return $self->node->findval(@vals); |
506
|
|
|
|
|
|
|
} |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
=head2 addchild |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
Title : addchild |
511
|
|
|
|
|
|
|
Usage : $struct->addchild(['name' => [['foo'=> 'bar1']]]); |
512
|
|
|
|
|
|
|
Function: add new child node to the current node. One can pass in a node, TagTree, |
513
|
|
|
|
|
|
|
or data structure; for instance, in the above, this would translate |
514
|
|
|
|
|
|
|
to (in XML): |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
bar1 |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
Returns : node |
521
|
|
|
|
|
|
|
Args : first arg = element name |
522
|
|
|
|
|
|
|
all other args are added as tag-value pairs |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
=cut |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
sub addchild { |
527
|
0
|
|
|
0
|
1
|
0
|
my ( $self, @vals ) = @_; |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
# check for element tag first (if no element, must be empty Data::Stag node) |
530
|
0
|
0
|
|
|
|
0
|
if ( !$self->element ) { |
|
|
0
|
|
|
|
|
|
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
# try to do the right thing; if more than one element, wrap in array ref |
533
|
0
|
0
|
|
|
|
0
|
@vals > 1 ? $self->value( \@vals ) : $self->value( $vals[0] ); |
534
|
0
|
|
|
|
|
0
|
return $self->{db}; |
535
|
|
|
|
|
|
|
} |
536
|
|
|
|
|
|
|
elsif ( !$self->node->ntnodes ) { |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
# if this is a terminal node, can't add to it (use set?) |
539
|
0
|
|
|
|
|
0
|
$self->throw("Can't add child to node; only terminal node is present!"); |
540
|
|
|
|
|
|
|
} |
541
|
|
|
|
|
|
|
else { |
542
|
0
|
|
|
|
|
0
|
return $self->node->addchild(@vals); |
543
|
|
|
|
|
|
|
} |
544
|
|
|
|
|
|
|
} |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
=head2 add |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
Title : add |
549
|
|
|
|
|
|
|
Usage : $struct->add('foo', 'bar1', 'bar2', 'bar3'); |
550
|
|
|
|
|
|
|
Function: add tag-value nodes to the current node. In the above, this would |
551
|
|
|
|
|
|
|
translate to (in XML): |
552
|
|
|
|
|
|
|
bar1 |
553
|
|
|
|
|
|
|
bar2 |
554
|
|
|
|
|
|
|
bar3 |
555
|
|
|
|
|
|
|
Returns : |
556
|
|
|
|
|
|
|
Args : first arg = element name |
557
|
|
|
|
|
|
|
all other args are added as tag-value pairs |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
=cut |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
sub add { |
562
|
0
|
|
|
0
|
1
|
0
|
my ( $self, @vals ) = @_; |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
# check for empty object and die for now |
565
|
0
|
0
|
|
|
|
0
|
if ( !$self->node->element ) { |
566
|
0
|
|
|
|
|
0
|
$self->throw("Can't add to terminal element!"); |
567
|
|
|
|
|
|
|
} |
568
|
0
|
|
|
|
|
0
|
return $self->node->add(@vals); |
569
|
|
|
|
|
|
|
} |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
=head2 set |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
Title : set |
574
|
|
|
|
|
|
|
Usage : $struct->set('foo','bar'); |
575
|
|
|
|
|
|
|
Function: sets a single tag-value pair in the current node. Note this |
576
|
|
|
|
|
|
|
differs from add() in that this replaces any data already present |
577
|
|
|
|
|
|
|
Returns : node |
578
|
|
|
|
|
|
|
Args : first arg = element name |
579
|
|
|
|
|
|
|
all other args are added as tag-value pairs |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
=cut |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
sub set { |
584
|
0
|
|
|
0
|
1
|
0
|
my ( $self, @vals ) = @_; |
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
# check for empty object |
587
|
0
|
0
|
|
|
|
0
|
if ( !$self->node->element ) { |
588
|
0
|
|
|
|
|
0
|
$self->throw("Can't add to tree; empty tree!"); |
589
|
|
|
|
|
|
|
} |
590
|
0
|
|
|
|
|
0
|
return $self->node->set(@vals); |
591
|
|
|
|
|
|
|
} |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
=head2 unset |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
Title : unset |
596
|
|
|
|
|
|
|
Usage : $struct->unset('foo'); |
597
|
|
|
|
|
|
|
Function: unsets all key-value pairs of the passed element from the |
598
|
|
|
|
|
|
|
current node |
599
|
|
|
|
|
|
|
Returns : node |
600
|
|
|
|
|
|
|
Args : element name |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
=cut |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
sub unset { |
605
|
0
|
|
|
0
|
1
|
0
|
my ( $self, @vals ) = @_; |
606
|
0
|
|
|
|
|
0
|
return $self->node->unset(@vals); |
607
|
|
|
|
|
|
|
} |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
=head2 free |
610
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
Title : free |
612
|
|
|
|
|
|
|
Usage : $struct->free |
613
|
|
|
|
|
|
|
Function: removes all data from the current node |
614
|
|
|
|
|
|
|
Returns : |
615
|
|
|
|
|
|
|
Args : |
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
=cut |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
sub free { |
620
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
621
|
0
|
|
|
|
|
0
|
return $self->node->free; |
622
|
|
|
|
|
|
|
} |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
=head2 hash |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
Title : hash |
627
|
|
|
|
|
|
|
Usage : $struct->hash; |
628
|
|
|
|
|
|
|
Function: turns the tag-value tree into a hash, all data values are array refs |
629
|
|
|
|
|
|
|
Returns : hash |
630
|
|
|
|
|
|
|
Args : first arg = element name |
631
|
|
|
|
|
|
|
all other args are added as tag-value pairs |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
=cut |
634
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
sub hash { |
636
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
637
|
0
|
|
|
|
|
0
|
return $self->node->hash; |
638
|
|
|
|
|
|
|
} |
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
=head2 pairs |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
Title : pairs |
643
|
|
|
|
|
|
|
Usage : $struct->pairs; |
644
|
|
|
|
|
|
|
Function: turns the tag-value tree into a hash, all data values are scalar |
645
|
|
|
|
|
|
|
Returns : hash |
646
|
|
|
|
|
|
|
Args : first arg = element name |
647
|
|
|
|
|
|
|
all other args are added as tag-value pairs, note that duplicates |
648
|
|
|
|
|
|
|
will be lost |
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
=cut |
651
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
sub pairs { |
653
|
4
|
|
|
4
|
1
|
1610
|
my ($self) = @_; |
654
|
4
|
|
|
|
|
9
|
return $self->node->pairs; |
655
|
|
|
|
|
|
|
} |
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
=head2 qmatch |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
Title : qmatch |
660
|
|
|
|
|
|
|
Usage : @persons = $s->qmatch('person', ('name'=>'fred')); |
661
|
|
|
|
|
|
|
Function : returns all elements in the node tree which match the |
662
|
|
|
|
|
|
|
element name and the key-value pair |
663
|
|
|
|
|
|
|
Returns : Array of nodes |
664
|
|
|
|
|
|
|
Args : return-element str, match-element str, match-value str |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
=cut |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
sub qmatch { |
669
|
0
|
|
|
0
|
1
|
0
|
my ( $self, @vals ) = @_; |
670
|
0
|
|
|
|
|
0
|
return $self->node->qmatch(@vals); |
671
|
|
|
|
|
|
|
} |
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
=head2 tnodes |
674
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
Title : tnodes |
676
|
|
|
|
|
|
|
Usage : @termini = $s->tnodes; |
677
|
|
|
|
|
|
|
Function : returns all terminal nodes below this node |
678
|
|
|
|
|
|
|
Returns : Array of nodes |
679
|
|
|
|
|
|
|
Args : return-element str, match-element str, match-value str |
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
=cut |
682
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
sub tnodes { |
684
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
685
|
0
|
|
|
|
|
0
|
return $self->node->tnodes; |
686
|
|
|
|
|
|
|
} |
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
=head2 ntnodes |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
Title : ntnodes |
691
|
|
|
|
|
|
|
Usage : @termini = $s->ntnodes; |
692
|
|
|
|
|
|
|
Function : returns all nonterminal nodes below this node |
693
|
|
|
|
|
|
|
Returns : Array of nodes |
694
|
|
|
|
|
|
|
Args : return-element str, match-element str, match-value str |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
=cut |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
sub ntnodes { |
699
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
700
|
0
|
|
|
|
|
0
|
return $self->node->ntnodes; |
701
|
|
|
|
|
|
|
} |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
=head2 StructureValue-like methods |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
=cut |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
=head2 get_all_values |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
Title : get_all_values |
710
|
|
|
|
|
|
|
Usage : @termini = $s->get_all_values; |
711
|
|
|
|
|
|
|
Function : returns all terminal node values |
712
|
|
|
|
|
|
|
Returns : Array of values |
713
|
|
|
|
|
|
|
Args : return-element str, match-element str, match-value str |
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
This is meant to emulate the values one would get from StructureValue's |
716
|
|
|
|
|
|
|
get_all_values() method. Note, however, using this method dissociates the |
717
|
|
|
|
|
|
|
tag-value relationship (i.e. you only get the value list, no elements) |
718
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
=cut |
720
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
sub get_all_values { |
722
|
4
|
|
|
4
|
1
|
428
|
my $self = shift; |
723
|
4
|
|
|
|
|
40
|
my @kids = $self->children; |
724
|
4
|
|
|
|
|
208
|
my @vals; |
725
|
4
|
|
|
|
|
23
|
while ( my $val = shift @kids ) { |
726
|
92
|
100
|
|
|
|
933
|
( ref $val ) ? push @kids, $val->children : push @vals, $val; |
727
|
|
|
|
|
|
|
} |
728
|
4
|
|
|
|
|
29
|
return @vals; |
729
|
|
|
|
|
|
|
} |
730
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
1; |