Bio::DB::Universal: move into its own distribution
[bioperl-live.git] / Bio / OntologyIO / dagflat.pm
blob52702720888af8c4b500b432f23bba9864733795
2 # BioPerl module for Bio::OntologyIO::dagflat
4 # Please direct questions and support issues to <bioperl-l@bioperl.org>
6 # Cared for by Hilmar Lapp, hlapp at gmx.net
8 # (c) Christian M. Zmasek, czmasek-at-burnham.org, 2002.
9 # (c) Hilmar Lapp, hlapp at gmx.net, 2003.
10 # (c) GNF, Genomics Institute of the Novartis Research Foundation, 2002.
12 # You may distribute this module under the same terms as perl itself.
13 # Refer to the Perl Artistic License (see the license accompanying this
14 # software package, or see http://www.perl.com/language/misc/Artistic.html)
15 # for the terms under which you may use, modify, and redistribute this module.
17 # THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
18 # WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 # MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 # You may distribute this module under the same terms as perl itself
23 # POD documentation - main docs before the code
25 =head1 NAME
27 Bio::OntologyIO::dagflat - a base class parser for GO flat-file type formats
29 =head1 SYNOPSIS
31 use Bio::OntologyIO;
33 # do not use directly -- use via Bio::OntologyIO
34 # e.g., the GO parser is a simple extension of this class
35 my $parser = Bio::OntologyIO->new
36 ( -format => "go",
37 -defs_file => "/home/czmasek/GO/GO.defs",
38 -files => ["/home/czmasek/GO/component.ontology",
39 "/home/czmasek/GO/function.ontology",
40 "/home/czmasek/GO/process.ontology"] );
42 my $go_ontology = $parser->next_ontology();
44 my $IS_A = Bio::Ontology::RelationshipType->get_instance( "IS_A" );
45 my $PART_OF = Bio::Ontology::RelationshipType->get_instance( "PART_OF" );
46 my $RELATED_TO = Bio::Ontology::RelationshipType->get_instance( "RELATED_TO" );
48 =head1 DESCRIPTION
50 Needs Graph.pm from CPAN.
52 =head1 FEEDBACK
54 =head2 Mailing Lists
56 User feedback is an integral part of the evolution of this and other
57 Bioperl modules. Send your comments and suggestions preferably to the
58 Bioperl mailing lists Your participation is much appreciated.
60 bioperl-l@bioperl.org - General discussion
61 http://bioperl.org/wiki/Mailing_lists - About the mailing lists
63 =head2 Support
65 Please direct usage questions or support issues to the mailing list:
67 I<bioperl-l@bioperl.org>
69 rather than to the module maintainer directly. Many experienced and
70 reponsive experts will be able look at the problem and quickly
71 address it. Please include a thorough description of the problem
72 with code and data examples if at all possible.
74 =head2 Reporting Bugs
76 Report bugs to the Bioperl bug tracking system to help us keep track
77 the bugs and their resolution. Bug reports can be submitted via the
78 web:
80 https://github.com/bioperl/bioperl-live/issues
82 =head1 AUTHOR
84 Christian M. Zmasek
86 Email: czmasek-at-burnham.org or cmzmasek@yahoo.com
88 WWW: http://monochrome-effect.net/
90 Address:
92 Genomics Institute of the Novartis Research Foundation
93 10675 John Jay Hopkins Drive
94 San Diego, CA 92121
96 =head2 CONTRIBUTOR
98 Hilmar Lapp, hlapp at gmx.net
100 =head1 APPENDIX
102 The rest of the documentation details each of the object
103 methods. Internal methods are usually preceded with a _
105 =cut
108 # Let the code begin...
111 package Bio::OntologyIO::dagflat;
113 use strict;
115 use Bio::Root::IO;
116 use Bio::Ontology::OBOEngine;
117 use Bio::Ontology::Ontology;
118 use Bio::Ontology::OntologyStore;
119 use Bio::Ontology::TermFactory;
120 use Bio::Annotation::DBLink;
122 use constant TRUE => 1;
123 use constant FALSE => 0;
126 use base qw(Bio::OntologyIO);
129 =head2 new
131 Title : new
132 Usage : $parser = Bio::OntologyIO->new(
133 -format => "go",
134 -defs_file => "/path/to/GO.defs",
135 -files => ["/path/to/component.ontology",
136 "/path/to/function.ontology",
137 "/path/to/process.ontology"] );
138 Function: Creates a new dagflat parser.
139 Returns : A new dagflat parser object, implementing Bio::OntologyIO.
140 Args : -defs_file => the name of the file holding the term
141 definitions
142 -files => a single ontology flat file holding the
143 term relationships, or an array ref holding
144 the file names (for GO, there will usually be
145 3 files: component.ontology, function.ontology,
146 process.ontology)
147 -file => if there is only a single flat file, it may
148 also be specified via the -file parameter
149 -ontology_name => the name of the ontology; if not specified the
150 parser will auto-discover it by using the term
151 that starts with a $, and converting underscores
152 to spaces
153 -engine => the Bio::Ontology::OntologyEngineI object
154 to be reused (will be created otherwise); note
155 that every Bio::Ontology::OntologyI will
156 qualify as well since that one inherits from the
157 former.
159 See L<Bio::OntologyIO>.
161 =cut
163 # in reality, we let OntologyIO::new do the instantiation, and override
164 # _initialize for all initialization work
165 sub _initialize {
166 my ($self, %arg) = @_;
168 my ( $defs_file_name,$files,$defs_url,$url,$name,$eng ) =
169 $self->_rearrange([qw( DEFS_FILE
170 FILES
171 DEFS_URL
173 ONTOLOGY_NAME
174 ENGINE)
176 %arg );
178 delete($arg{-url}); #b/c GO has 3 files...
180 $self->SUPER::_initialize( %arg );
182 $self->_done( FALSE );
183 $self->_not_first_record( FALSE );
184 $self->_term( "" );
185 delete $self->{'_ontologies'};
187 # ontology engine (and possibly name if it's an OntologyI)
188 $eng = Bio::Ontology::OBOEngine->new() unless $eng;
189 if($eng->isa("Bio::Ontology::OntologyI")) {
190 $self->ontology_name($eng->name());
191 $eng = $eng->engine() if $eng->can('engine');
193 $self->_ont_engine($eng);
195 # flat files to parse
196 if(defined($defs_file_name) && defined($defs_url)){
197 $self->throw('cannot provide both -defs_file and -defs_url');
198 } else {
199 defined($defs_file_name) && $self->defs_file( $defs_file_name );
200 defined($defs_url) && $self->defs_url( $defs_url );
203 if(defined($files) && defined($url)){
204 } elsif(defined($files)){
205 $self->{_flat_files} = $files ? ref($files) ? $files : [$files] : [];
206 } elsif(defined($url)){
207 $self->url($url);
210 # ontology name (overrides implicit one through OntologyI engine)
211 $self->ontology_name($name) if $name;
213 } # _initialize
215 =head2 ontology_name
217 Title : ontology_name
218 Usage : $obj->ontology_name($newval)
219 Function: Get/set the name of the ontology parsed by this module.
220 Example :
221 Returns : value of ontology_name (a scalar)
222 Args : on set, new value (a scalar or undef, optional)
225 =cut
227 sub ontology_name{
228 my $self = shift;
230 return $self->{'ontology_name'} = shift if @_;
231 return $self->{'ontology_name'};
235 =head2 parse
237 Title : parse()
238 Usage : $parser->parse();
239 Function: Parses the files set with "new" or with methods
240 defs_file and _flat_files.
242 Normally you should not need to call this method as it will
243 be called automatically upon the first call to
244 next_ontology().
246 Returns : [Bio::Ontology::OntologyEngineI]
247 Args :
249 =cut
251 sub parse {
252 my $self = shift;
254 #warn "PARSING";
255 # setup the default term factory if not done by anyone yet
256 $self->term_factory(Bio::Ontology::TermFactory->new(
257 -type => "Bio::Ontology::Term"))
258 unless $self->term_factory();
260 # create the ontology object itself
261 my $ont = Bio::Ontology::Ontology->new(-name => $self->ontology_name(),
262 -engine => $self->_ont_engine());
264 # parse definitions
265 while( my $term = $self->_next_term() ) {
266 $self->_add_term( $term, $ont );
269 # set up the ontology of the relationship types
270 foreach ($self->_part_of_relationship(), $self->_is_a_relationship(), $self->_related_to_relationship()) {
271 $_->ontology($ont);
274 # pre-seed the IO system with the first flat file if -file wasn't provided
275 if(! $self->_fh) {
276 if($self->url){
277 if(ref($self->url) eq 'ARRAY'){
278 #warn "BA";
279 foreach my $url (@{ $self->url }){
280 #warn $url;
281 #warn $ont;
282 #warn scalar($ont->get_all_terms());
283 $self->_initialize_io(-url => $url);
284 $self->_parse_flat_file($ont);
286 $self->close();
287 } else {
288 $self->_initialize_io(-url => $self->url);
290 } elsif($self->_flat_files){
291 $self->_initialize_io(-file => shift(@{$self->_flat_files()}));
295 while($self->_fh) {
296 $self->_parse_flat_file($ont);
297 # advance to next flat file if more are available
298 if(@{$self->_flat_files()}) {
299 $self->close();
300 $self->_initialize_io(-file => shift(@{$self->_flat_files()}));
301 } else {
302 last; # nothing else to parse so terminate the loop
305 $self->_add_ontology($ont);
307 # not needed anywhere, only because of backward compatibility
308 return $self->_ont_engine();
309 } # parse
311 =head2 next_ontology
313 Title : next_ontology
314 Usage :
315 Function: Get the next available ontology from the parser. This is the
316 method prescribed by Bio::OntologyIO.
317 Example :
318 Returns : An object implementing Bio::Ontology::OntologyI, and undef if
319 there is no more ontology in the input.
320 Args :
323 =cut
325 sub next_ontology {
326 my $self = shift;
328 # parse if not done already
329 $self->parse() unless exists($self->{'_ontologies'});
330 # return next available ontology
331 if(exists($self->{'_ontologies'})){
332 my $ont = shift (@{$self->{'_ontologies'}});
333 if($ont){
334 my $store = Bio::Ontology::OntologyStore->new();
335 $store->register_ontology($ont);
336 return $ont;
339 return;
342 =head2 defs_file
344 Title : defs_file
345 Usage : $parser->defs_file( "GO.defs" );
346 Function: Set/get for the term definitions filename.
347 Returns : The term definitions file name [string].
348 Args : On set, the term definitions file name [string] (optional).
350 =cut
352 sub defs_file {
353 my $self = shift;
355 if ( @_ ) {
356 my $f = shift;
357 $self->{ "_defs_file_name" } = $f;
358 $self->_defs_io->close() if $self->_defs_io();
359 if(defined($f)) {
360 $self->_defs_io( Bio::Root::IO->new( -input => $f ) );
363 return $self->{ "_defs_file_name" };
364 } # defs_file
366 sub defs_url {
367 my $self = shift;
368 my $val = shift;
369 if(defined($val)){
370 $self->{'_defs_url'} = $val;
372 $self->_defs_io->close() if $self->_defs_io();
373 $self->_defs_io( Bio::Root::IO->new( -url => $val ) );
375 return $self->{'_defs_url'};
378 sub url {
379 my $self = shift;
380 my $val = shift;
381 if(defined($val)){
382 $self->{'_url'} = $val;
384 return $self->{'_url'};
387 =head2 close
389 Title : close
390 Usage :
391 Function: Closes this ontology stream and associated file handles.
393 Clients should call this method especially when they write
394 ontologies.
396 We need to override this here in order to close the file
397 handle for the term definitions file.
399 Example :
400 Returns : none
401 Args : none
404 =cut
406 sub close{
407 my $self = shift;
409 # first call the inherited implementation
410 $self->SUPER::close();
411 # then close the defs file io (if there is one)
412 $self->_defs_io->close() if $self->_defs_io();
415 =head2 _flat_files
417 Title : _flat_files
418 Usage : $files_to_parse = $parser->_flat_files();
419 Function: Get the array of ontology flat files that need to be parsed.
421 Note that this array will decrease in elements over the
422 parsing process. Therefore, it\'s value outside of this
423 module will be limited. Also, be careful not to alter the
424 array unless you know what you are doing.
426 Returns : a reference to an array of zero or more strings
427 Args : none
429 =cut
431 sub _flat_files {
432 my $self = shift;
434 $self->{_flat_files} = [] unless exists($self->{_flat_files});
435 return $self->{_flat_files};
439 # INTERNAL METHODS
440 # ----------------
442 =head2 _defs_io
444 Title : _defs_io
445 Usage : $obj->_defs_io($newval)
446 Function: Get/set the Bio::Root::IO instance representing the
447 definition file, if provided (see defs_file()).
448 Example :
449 Returns : value of _defs_io (a Bio::Root::IO object)
450 Args : on set, new value (a Bio::Root::IO object or undef, optional)
452 =cut
454 sub _defs_io{
455 my $self = shift;
457 return $self->{'_defs_io'} = shift if @_;
458 return $self->{'_defs_io'};
461 sub _add_ontology {
462 my $self = shift;
463 $self->{'_ontologies'} = [] unless exists($self->{'_ontologies'});
464 foreach my $ont (@_) {
465 $self->throw(ref($ont)." does not implement Bio::Ontology::OntologyI")
466 unless ref($ont) && $ont->isa("Bio::Ontology::OntologyI");
467 # the ontology name may have been auto-discovered while parsing
468 # the file
469 $ont->name($self->ontology_name) unless $ont->name();
470 push(@{$self->{'_ontologies'}}, $ont);
474 # This simply delegates. See SimpleGOEngine.
475 sub _add_term {
476 my ( $self, $term, $ont ) = @_;
477 $term->ontology($ont) if $ont && (! $term->ontology);
478 $self->_ont_engine()->add_term( $term );
479 } # _add_term
483 # This simply delegates. See SimpleGOEngine
484 sub _part_of_relationship {
485 my $self = shift;
487 return $self->_ont_engine()->part_of_relationship(@_);
488 } # _part_of_relationship
492 # This simply delegates. See SimpleGOEngine
493 sub _is_a_relationship {
494 my $self = shift;
496 return $self->_ont_engine()->is_a_relationship(@_);
497 } # _is_a_relationship
499 # This simply delegates. See SimpleGOEngine
500 sub _related_to_relationship {
501 my $self = shift;
503 return $self->_ont_engine()->related_to_relationship(@_);
504 } # _is_a_relationship
508 # This simply delegates. See SimpleGOEngine
509 sub _add_relationship {
510 my ( $self, $parent, $child, $type, $ont ) = @_;
512 # note the triple terminology (subject,predicate,object) corresponds to
513 # (child,type,parent)
514 $self->_ont_engine()->add_relationship( $child, $type, $parent, $ont );
517 } # _add_relationship
520 # This simply delegates. See SimpleGOEngine
521 sub _has_term {
522 my $self = shift;
524 return $self->_ont_engine()->has_term( @_ );
525 } # _add_term
529 # This parses the relationships files
530 sub _parse_flat_file {
531 my $self = shift;
532 my $ont = shift;
534 my @stack = ();
535 my $prev_spaces = -1;
536 my $prev_term = "";
538 while ( my $line = $self->_readline() ) {
540 if ( $line =~ /^!/ ) {
541 next;
544 # split into term specifications
545 my @termspecs = split(/ (?=[%<])/, $line);
546 # the first element is whitespace only
547 shift(@termspecs) if $termspecs[0] =~ /^\s*$/;
549 # parse out the focus term
550 my $current_term = $self->_get_first_termid( $termspecs[0] );
551 my @syns = $self->_get_synonyms( $termspecs[0] );
552 my @sec_go_ids = $self->_get_secondary_termids( $termspecs[0] );
553 my @cross = $self->_get_db_cross_refs( $termspecs[0] );
554 my @cross_refs;
555 foreach my $cross_ref (@cross) {
556 $cross_ref eq $current_term && next;
557 push(@cross_refs, $cross_ref);
560 # parse out the parents of the focus term
561 shift(@termspecs);
562 my @isa_parents = ();
563 my @partof_parents = ();
564 foreach my $parent (@termspecs) {
565 if (index($parent, "%") == 0) {
566 push(@isa_parents, $self->_get_first_termid($parent));
567 } elsif (index($parent, "<") == 0) {
568 push(@partof_parents, $self->_get_first_termid($parent));
569 } else {
570 $self->warn("unhandled relationship type in '".$parent."'");
574 if ( ! $self->_has_term( $current_term ) ) {
575 my $term =$self->_create_ont_entry($self->_get_name($line,
576 $current_term),
577 $current_term );
578 $self->_add_term( $term, $ont );
581 my $current_term_object = $self->_ont_engine()->get_terms( $current_term );
582 my $anno = $self->_to_annotation(\@cross_refs);
583 $current_term_object->add_dbxref(-dbxrefs => $anno);
584 $current_term_object->add_secondary_id( @sec_go_ids );
585 $current_term_object->add_synonym( @syns );
586 unless ( $line =~ /^\$/ ) {
587 $current_term_object->ontology( $ont );
589 foreach my $parent ( @isa_parents ) {
590 if ( ! $self->_has_term( $parent ) ) {
591 my $term = $self->_create_ont_entry($self->_get_name($line,
592 $parent),
593 $parent );
594 $self->_add_term( $term, $ont );
597 $self->_add_relationship( $parent,
598 $current_term,
599 $self->_is_a_relationship(),
600 $ont);
603 foreach my $parent ( @partof_parents ) {
604 if ( ! $self->_has_term( $parent ) ) {
605 my $term = $self->_create_ont_entry($self->_get_name($line,
606 $parent),
607 $parent );
608 $self->_add_term( $term, $ont );
611 $self->_add_relationship( $parent,
612 $current_term,
613 $self->_part_of_relationship(),
614 $ont);
617 my $current_spaces = $self->_count_spaces( $line );
619 if ( $current_spaces != $prev_spaces ) {
621 if ( $current_spaces == $prev_spaces + 1 ) {
622 push( @stack, $prev_term );
623 } elsif ( $current_spaces < $prev_spaces ) {
624 my $n = $prev_spaces - $current_spaces;
625 for ( my $i = 0; $i < $n; ++$i ) {
626 pop( @stack );
628 } else {
629 $self->throw( "format error (file ".$self->file.")" );
633 my $parent = $stack[ @stack - 1 ];
635 # add a relationship if the line isn\'t the one with the root term
636 # of the ontology (which is also the name of the ontology)
637 if ( index($line,'$') != 0 ) {
638 #adding @reltype@ syntax
639 if ( $line !~ /^\s*([<%~]|\@\w+?\@)/ ) {
640 $self->throw( "format error (file ".$self->file.") offending line:\n$line" );
643 my($relstring) = $line =~ /^\s*([<%~]|\@[^\@]+?\@)/;
645 my $reltype;
647 if ($relstring eq '<') {
648 $reltype = $self->_part_of_relationship;
649 } elsif ($relstring eq '%') {
650 $reltype = $self->_is_a_relationship;
651 } elsif ($relstring eq '~') {
652 $reltype = $self->_related_to_relationship;
653 } else {
654 $relstring =~ s/\@//g;
655 if ($self->_ont_engine->get_relationship_type($relstring)) {
656 $reltype = $self->_ont_engine->get_relationship_type($relstring);
657 } else {
658 $self->_ont_engine->add_relationship_type($relstring, $ont);
659 $reltype = $self->_ont_engine->get_relationship_type($relstring);
663 #my $reltype = ($line =~ /^\s*</) ?
664 #$self->_part_of_relationship() :
665 #$self->_is_a_relationship();
666 $self->_add_relationship( $parent, $current_term, $reltype, $ont);
669 $prev_spaces = $current_spaces;
670 $prev_term = $current_term;
672 return $ont;
673 } # _parse_relationships_file
677 # Parses the 1st term id number out of line.
678 sub _get_first_termid {
679 my ( $self, $line ) = @_;
680 if ( $line =~ /;\s*([A-Z_]{1,8}:\d{1,})/ ) {
681 # if ( $line =~ /;\s*(\w+:\w+)/ ) {
682 return $1;
684 else {
685 $self->throw( "format error: no term id in line \"$line\"" );
688 } # _get_first_termid
692 # Parses the name out of line.
693 sub _get_name {
694 my ( $self, $line, $termid ) = @_;
696 if ( $line =~ /([^;<%~]+);\s*$termid/ ) {
697 my $name = $1;
698 # remove trailing and leading whitespace
699 $name =~ s/\s+$//;
700 $name =~ s/^\s+//;
701 $name =~ s/\@.+?\@//;
702 # remove leading dollar character; also we default the name of the
703 # ontology to this name unless it is preset to something else
704 if(index($name,'$') == 0) {
705 $name = substr($name,1);
706 # replace underscores by spaces for setting the ontology name
707 $self->ontology_name(join(" ",split(/_/,$name)))
708 unless $self->ontology_name();
710 return $name;
712 else {
713 return;
715 } # _get_name
718 # Parses the synonyms out of line.
719 sub _get_synonyms {
720 my ( $self, $line ) = @_;
722 my @synonyms = ();
724 while ( $line =~ /synonym\s*:\s*([^;<%~]+)/g ) {
725 my $syn = $1;
726 $syn =~ s/\s+$//;
727 $syn =~ s/^\s+//;
728 push( @synonyms, $syn );
730 return @synonyms;
732 } # _get_synonyms
736 # Parses the db cross refs out of line.
737 sub _get_db_cross_refs {
738 my ( $self, $line ) = @_;
740 my @refs = ();
742 while ( $line =~ /;([^;<%~:]+:[^;<%~:]+)/g ) {
743 my $ref = $1;
744 if ( $ref =~ /synonym/ || $ref =~ /[A-Z]{1,8}:\d{3,}/ ) {
745 next;
747 $ref =~ s/\s+$//;
748 $ref =~ s/^\s+//;
750 $ref = $self->unescape( $ref );
752 push( @refs, $ref ) if defined $ref;
754 return @refs;
759 # Parses the secondary go ids out of a line
760 sub _get_secondary_termids {
761 my ( $self, $line ) = @_;
762 my @secs = ();
764 # while ( $line =~ /,\s*([A-Z]{1,8}:\d{3,})/g ) {
765 while ( $line =~ /,\s*(\w+:\w+)/g ) {
766 my $sec = $1;
767 push( @secs, $sec );
769 return @secs;
771 } # _get_secondary_termids
774 # Counts the spaces at the beginning of a line in the relationships files
775 sub _count_spaces {
776 my ( $self, $line ) = @_;
778 if ( $line =~ /^(\s+)/ ) {
779 return length( $1 );
781 else {
782 return 0;
784 } # _count_spaces
787 # "next" method for parsing the defintions file
788 sub _next_term {
789 my ( $self ) = @_;
791 if ( ($self->_done() == TRUE) || (! $self->_defs_io())) {
792 return;
795 my $line = "";
796 my $termid = "";
797 my $next_term = $self->_term();
798 my $def = "";
799 my $comment = "";
800 my @def_refs = ();
801 my $isobsolete;
803 while( $line = ( $self->_defs_io->_readline() ) ) {
804 if ( $line !~ /\S/
805 || $line =~ /^\s*!/ ) {
806 next;
808 elsif ( $line =~ /^\s*term:\s*(.+)/ ) {
809 $self->_term( $1 );
810 last if $self->_not_first_record();
811 $next_term = $1;
812 $self->_not_first_record( TRUE );
814 elsif ( $line =~ /^\s*[a-z]{0,8}id:\s*(.+)/ ) {
815 $termid = $1;
817 elsif ( $line =~ /^\s*definition:\s*(.+)/ ) {
818 $def = $self->unescape($1);
819 $isobsolete = 1 if index($def,"OBSOLETE") == 0;
821 elsif ( $line =~ /^\s*definition_reference:\s*(.+)/ ) {
822 push( @def_refs, $self->unescape($1) );
824 elsif ( $line =~ /^\s*comment:\s*(.+)/ ) {
825 $comment = $self->unescape($1);
828 $self->_done( TRUE ) unless $line; # we'll come back until done
829 return $self->_create_ont_entry( $next_term, $termid, $def,
830 $comment, \@def_refs, $isobsolete);
831 } # _next_term
835 # Holds the GO engine to be parsed into
836 sub _ont_engine {
837 my ( $self, $value ) = @_;
839 if ( defined $value ) {
840 $self->{ "_ont_engine" } = $value;
843 return $self->{ "_ont_engine" };
844 } # _ont_engine
847 # Used to create ontology terms.
848 # Arguments: name, id
849 sub _create_ont_entry {
850 my ( $self, $name, $termid, $def, $cmt, $dbxrefs, $obsolete ) = @_;
852 if((!defined($obsolete)) && (index(lc($name),"obsolete") == 0)) {
853 $obsolete = 1;
855 my $anno = $self->_to_annotation($dbxrefs);
856 my $term = $self->term_factory->create_object(-name => $name,
857 -identifier => $termid,
858 -definition => $def,
859 -comment => $cmt,
860 -dbxrefs => $anno,
861 -is_obsolete => $obsolete);
863 return $term;
864 } # _create_ont_entry
868 # Holds whether first record or not
869 sub _not_first_record {
870 my ( $self, $value ) = @_;
872 if ( defined $value ) {
873 $self->{ "_not_first_record" } = $value;
876 return $self->{ "_not_first_record" };
877 } # _not_first_record
881 # Holds whether done or not
882 sub _done {
883 my ( $self, $value ) = @_;
885 if ( defined $value ) {
886 $self->{ "_done" } = $value;
889 return $self->{ "_done" };
890 } # _done
893 # Holds a term.
894 sub _term {
895 my ( $self, $value ) = @_;
897 if ( defined $value ) {
898 $self->{ "_term" } = $value;
901 return $self->{ "_term" };
902 } # _term
904 # convert simple strings to Bio::Annotation::DBLinks
905 sub _to_annotation {
906 my ($self , $links) = @_;
907 return unless $links;
908 my @dbxrefs;
909 for my $string (@{$links}) {
910 my ($db, $id) = split(':',$string);
911 push @dbxrefs, Bio::Annotation::DBLink->new(-database => $db, -primary_id => $id);
913 return \@dbxrefs;