6 use CXGN
::Chado
::Cvterm
;
7 use CXGN
::Scrap
::AjaxPage
;
10 my $doc = CXGN
::Scrap
::AjaxPage
->new();
11 $doc->send_http_header();
14 my ( $cv_accession, $action, $indent ) = $doc->get_encoded_arguments("cv_accession", "action", "indent");
16 my $dbh = CXGN
::DB
::Connection
->new();
17 $cv_accession =~ tr/a-z/A-Z/;
20 if($action eq "specific") {
21 my $cv_term = CXGN
::Chado
::Cvterm
->new_with_accession( $dbh, $cv_accession );
22 my $obsolete = "false";
23 if( $cv_term->get_cvterm_id() ne "" && $cv_term->term_is_obsolete() eq "true" ) {
28 if( $cv_term->get_cvterm_id() ne "" && $obsolete ne "true" ) {
31 my @roots = CXGN
::Chado
::Cvterm
::get_roots
($dbh, $cv_term->get_db_name() );
32 foreach my $new_root ( @roots ) {
33 push( @roots_list, $new_root );
35 my $rootNumber = scalar( @roots_list );
37 # Paths will be stored as an array of arrays
40 # Explicitly initialize the first array, the rest will be dynamic
42 push( @init, [$cv_term, undef] );
43 unshift( @paths, \
@init );
46 my $complete = "false";
47 # Will become true if and only if every path traces back to a root
49 # Monitors how many paths are done -- when all are done, complete becomes true
51 # If searching for a root, the path is already done
52 FINDIFROOT
: for( my $i = 0; $i < scalar( @roots_list ); $i++ ) {
53 if( $init[0]->[0]->get_accession() eq $roots_list[$i]->get_accession() ) {
54 unshift( @init, "done" );
63 while( $complete ne "true" ) {
64 # Identify latest term in each path
65 my $pathNumber = scalar( @paths );
66 for( my $i = 0; $i < $pathNumber; $i++ ) {
67 my $pathArrayRef = $paths[$i];
68 my @workingPath = @
$pathArrayRef;
70 my $nextTerm = "done";
71 if( ref( $workingPath[0] ) eq "ARRAY" ) {
72 $nextTerm = $workingPath[0]->[0];
75 # Read only paths that are not done, this saves time
76 if( $nextTerm ne "done" ) {
77 my @parents = $nextTerm->get_parents();
78 my $parentNumber = scalar( @parents );
80 if( $parentNumber > 1 ) {
81 # Take out original path, then push copies of original path with new parents into paths list
83 my $originalPath = splice( @paths, $index, 1 );
85 ROOTCHECKER
: for( my $j = 0; $j < $parentNumber; $j++ ) {
86 my @nextPath = @
$originalPath;
88 unshift( @nextPath, $parents[$j] );
89 for( my $k = 0; $k < scalar( @roots_list ); $k++ ) {
90 if( $nextPath[0]->[0]->get_accession() eq $roots_list[$k]->get_accession() ) {
91 $nextPath[0] = [ $roots_list[$k], undef ];
92 unshift( @nextPath, "done" );
93 push( @paths, \
@nextPath );
98 push( @paths, \
@nextPath );
103 # Simple: put the parent in the array and see if it's a root or not
104 unshift( @workingPath, $parents[0] );
106 ROOTCHECK
: for( my $j = 0; $j < scalar( @roots_list ); $j++ ) {
107 if( $workingPath[0]->[0]->get_accession() eq $roots_list[$j]->get_accession() ) {
108 $workingPath[0] = [ $roots_list[$j], undef ];
109 unshift( @workingPath, "done" );
114 $paths[$i] = \
@workingPath;
119 my $test = scalar( @paths );
120 if( $doneCounter == $test ) {
126 my $xmlRoot = XML
::Twig
::Elt
->new('specific');
127 my $treeRootTag = "term";
128 my %termIndentHash = ();
130 for( my $i = 0; $i < scalar( @paths ); $i++ ) {
131 my $pathRef = $paths[$i];
132 my @path = @
$pathRef;
134 for( my $j = 1; $j < scalar( @path ); $j++ ) {
135 my $treeRootContent = $paths[$i]->[$j]->[0]->get_db_name().":".$paths[$i]->[$j]->[0]->get_accession();
136 my $fullName = $treeRootContent;
137 $treeRootContent .= ' -- '.$paths[$i]->[$j]->[0]->get_cvterm_name();
139 my $elementID = $j."--".$fullName;
141 my $next = XML
::Twig
::Elt
->new( $treeRootTag, $treeRootContent );
142 $next->set_att( id
=> $fullName );
143 $next->set_att( divID
=> $elementID );
144 $next->set_att( indent
=> $j );
146 my $childNumber = $paths[$i]->[$j]->[0]->count_children();
147 $next->set_att( children
=> $childNumber );
149 if( scalar( $xmlRoot->descendants() ) > 0 ) {
150 my $element = $xmlRoot;
151 while( $element = $element->next_elt( '#ELT' ) ) {
153 my $previousRootContent = $paths[$i]->[$j-1]->[0]->get_db_name().":";
154 $previousRootContent .= $paths[$i]->[$j-1]->[0]->get_accession();
156 my $text = $element->text;
157 my $startIndex = index( $text, ":" ) + 1;
158 $text = substr( $text, $startIndex - 3, $startIndex + 7 );
160 my $idText = substr( $element->trimmed_text, 0, 10 );
161 my $idIndent = $element->att( 'indent' );
163 if( $text eq $previousRootContent ) {
164 my $newElement = "true";
166 if( exists $termIndentHash{$idText} ) {
167 if( !grep( $idIndent, @
{$termIndentHash{$idText}} ) ) {
168 push @
{ $termIndentHash{$idText}}, $idIndent;
172 if( $newElement ne "false" ) {
173 if( $next->att( 'indent' ) - $element->att( 'indent' ) == 1 ) {
174 eval{$next->paste( 'last_child', $element )};
175 $termIndentHash{$idText} = [$idIndent];
182 $next->paste( $xmlRoot );
183 $termIndentHash{$next->trimmed_text} = ["1"];
188 # Format and print XML tree
189 my $text = $xmlRoot->sprint;
191 $text =~ s
|>|>\n|g
; # Put newlines after tag boundaries
192 $text =~ s
|<|\n<|g
; # Put newlines before tag boundaries
193 $text =~ s
|>\n([A
-Z
])|>$1|g
; # Remove newlines when they come before an accession
195 my $newLineIndex = 0; # Remove blank lines by removing extra newlines; go through string multiple
196 while( $newLineIndex != -1 ) { # times if necessary
197 $text =~ s
|\n\n|\n|g
;
198 $newLineIndex = index( $text, "\n\n" );
201 $text =~ s
|(<term
[A
-Za
-z0
-9 _\
,\
<\
>\
+\
=\
/\'\"\:\t-]*)\n(</term
>)|$1$2|g
;
202 # Condense the final term of each path, and its end tag, onto one line for easy identification
214 if ($action eq "children") {
215 # Get all children of a term
216 $cv_term = CXGN
::Chado
::Cvterm
->new_with_accession($dbh, $cv_accession);
217 @term_list = $cv_term->get_children();
221 # This gets roots for a specific database
222 my @new_roots = CXGN
::Chado
::Cvterm
::get_roots
($dbh, $action);
223 foreach my $new_root (@new_roots) {
224 push @term_list, [ $new_root, undef ];
231 foreach my $t (@term_list) {
232 my $id = $t->[0]->get_db_name().":".$t->[0]->get_accession();
233 my $divID = $indent."--".$id;
234 my $childNumber = $t->[0]->count_children();
236 my $term = "<term children='$childNumber' divID='$divID' id='$id' indent='$indent'> ";
237 $term .= $t->[0]->get_db_name().":".$t->[0]->get_accession(). " -- ".$t->[0]->get_cvterm_name();
244 print $doc->footer();