--- loncom/xml/lonxml.pm 2000/06/26 21:35:20 1.3 +++ loncom/xml/lonxml.pm 2001/01/06 16:22:55 1.46 @@ -2,192 +2,414 @@ # XML Parser Module # # last modified 06/26/00 by Alexander Sakharuk +# 11/6 Gerd Kortemeyer +# 6/1/1 Gerd Kortemeyer -package Apache::lonxmlparser; - +package Apache::lonxml; +use vars +qw(@pwd $outputstack $redirection $textredirection $on_offimport @extlinks); use strict; use HTML::TokeParser; use Safe; -use Apache::lonstyleparser; +use Safe::Hole; +use Opcode; +use Apache::Constants qw(:common); + +sub register { + my $space; + my @taglist; + my $temptag; + ($space,@taglist) = @_; + foreach $temptag (@taglist) { + $Apache::lonxml::alltags{$temptag}=$space; + } +} + +use Apache::style; use Apache::lontexconvert; -use Apache::londefaulttags; +use Apache::run; +use Apache::londefdef; +use Apache::scripttag; #================================================== Main subroutine: xmlparse +@pwd=(); +$outputstack = ''; +$redirection = 1; +$textredirection = 1; +$on_offimport = 0; +@extlinks=(); sub xmlparse { - my ($target,$content_file_string,%style_for_target) = @_; - my $pars = HTML::TokeParser->new(\$content_file_string); + my ($target,$content_file_string,$safeinit,%style_for_target) = @_; + if ($target eq 'meta') { + $Apache::lonxml::textredirection = 0; + $Apache::lonxml::on_offimport = 1; + } else { + $Apache::lonxml::textredirection = 1; + $Apache::lonxml::on_offimport = 0; + } + my @pars = (); + @Apache::lonxml::pwd=(); + my $pwd=$ENV{'request.filename'}; + $pwd =~ s:/[^/]*$::; + &newparser(\@pars,\$content_file_string,$pwd); my $currentstring = ''; my $finaloutput = ''; my $newarg = ''; - my $tempostring = ''; - my $tempocont = ''; - my $safeeval = new Safe; + my $result; + my $safeeval = new Safe; + my $safehole = new Safe::Hole; + $safeeval->permit("entereval"); + $safeeval->permit(":base_math"); + $safeeval->deny(":base_io"); + $safehole->wrap(\&Apache::lonnet::EXT,$safeeval,'&EXT'); +#need to inspect this class of ops +# $safeeval->deny(":base_orig"); + $safeinit .= ';$external::target='.$target.';'; + $safeinit .= ';$external::randomseed='.&Apache::lonnet::rndseed().';'; + &Apache::run::run($safeinit,$safeeval); #-------------------- Redefinition of the target in the case of compound target ($target, my @tenta) = split('&&',$target); -#------------------------- Stack definition (in stack we have all current tags) - my @stack = (); my @parstack = (); + &initdepth; + my $token; + while ( $#pars > -1 ) { + while ($token = $pars[$#pars]->get_token) { + if ($token->[0] eq 'T') { + if ($Apache::lonxml::textredirection == 1) {$result=$token->[1];} + # $finaloutput .= &Apache::run::evaluate($token->[1],$safeeval,''); + } elsif ($token->[0] eq 'S') { + # if ($target eq 'meta' and $token->[2]->{metaout} eq 'ON') {$Apache::lonxml::textredirection = 1;} + # add tag to stack + push (@stack,$token->[1]); + # add parameters list to another stack + push (@parstack,&parstring($token)); + &increasedepth($token); + if (exists $style_for_target{$token->[1]}) { + + if ($Apache::lonxml::redirection == 1) { + $finaloutput .= &recurse($style_for_target{$token->[1]}, + $target,$safeeval,\%style_for_target, + @parstack); + } else { + $Apache::lonxml::outputstack .= &recurse($style_for_target{$token->[1]}, + $target,$safeeval,\%style_for_target, + @parstack); + } + + } else { + $result = &callsub("start_$token->[1]", $target, $token,\@parstack, + \@pars, $safeeval, \%style_for_target); + } + } elsif ($token->[0] eq 'E') { + #if ($target eq 'meta') {$Apache::lonxml::textredirection = 0;} + #clear out any tags that didn't end + while ($token->[1] ne $stack[$#stack] + && ($#stack > -1)) { + &Apache::lonxml::error("Unbalanced tags in resource $stack['-1']"); + pop @stack;pop @parstack;&decreasedepth($token); + } + + if (exists $style_for_target{'/'."$token->[1]"}) { -#------------------------------------- Parse input string (content_file_string) + if ($Apache::lonxml::redirection == 1) { + $finaloutput .= &recurse($style_for_target{'/'."$token->[1]"}, + $target,$safeeval,\%style_for_target, + @parstack); + } else { + $Apache::lonxml::outputstack .= &recurse($style_for_target{'/'."$token->[1]"}, + $target,$safeeval,\%style_for_target, + @parstack); + } + + } else { + $result = &callsub("end_$token->[1]", $target, $token, \@parstack, + \@pars,$safeeval, \%style_for_target); + } + } + if ($result ne "") { + if ( $#parstack > -1 ) { - my $token; + if ($Apache::lonxml::redirection == 1) { + $finaloutput .= &Apache::run::evaluate($result,$safeeval, + $parstack[$#parstack]); + } else { + $Apache::lonxml::outputstack .= &Apache::run::evaluate($result,$safeeval, + $parstack[$#parstack]); + } - while ($token = $pars->get_token) { - if ($token->[0] eq 'T') { - $finaloutput .= $token->[1]; - $tempocont .= $token->[1]; - } elsif ($token->[0] eq 'S') { -#------------------------------------------------------------- add tag to stack - push (@stack,$token->[1]); -#----------------------------------------- add parameters list to another stack - map {$tempostring .= "$_=$token->[2]->{$_},"} @{$token->[3]}; - push (@parstack,$tempostring); - $tempostring = ''; - - if (exists $style_for_target{$token->[1]}) { - -#---------------------------------------------------- use style file definition - - $newarg = $style_for_target{$token->[1]}; - - if (index($newarg,'script') != -1 ) { - my $pat = HTML::TokeParser->new(\$newarg); - my $tokenpat; - my $partstring = ''; - my $oustring = ''; - my $outputstring; - - while ($tokenpat = $pat->get_token) { - if ($tokenpat->[0] eq 'T') { - $oustring .= $tokenpat->[1]; - } elsif ($tokenpat->[0] eq 'S') { - if ($tokenpat->[1] eq 'script') { - while ($tokenpat = $pat->get_token and $tokenpat->[1] ne 'script') { - if ($tokenpat->[0] eq 'S') { - $partstring .= $tokenpat->[4]; - } elsif ($tokenpat->[0] eq 'T') { - $partstring .= $tokenpat->[1]; - } elsif ($tokenpat->[0] eq 'E') { - $partstring .= $tokenpat->[2]; - } - } - - map {$partstring =~ s/\$$_/$token->[2]->{$_}/g; } @{$token->[3]}; - - &run($partstring,$safeeval); - - $partstring = ''; - } elsif ($tokenpat->[1] eq 'evaluate') { - $outputstring = &evaluate($tokenpat->[2]{expression},$safeeval); - $oustring .= $outputstring; - } else { - $oustring .= $tokenpat->[4]; - } - } elsif ($tokenpat->[0] eq 'E' and $tokenpat->[1] ne 'evaluate') { - $oustring .= $tokenpat->[1]; - } + } else { + $finaloutput .= &Apache::run::evaluate($result,$safeeval,''); } - $newarg = $oustring; - } else { - map {$newarg =~ s/\$$_/$token->[2]->{$_}/g; } @{$token->[3]}; - } - $finaloutput .= $newarg; - } else { -#------------------------------------------------ use default definition of tag - my $sub="start_$token->[1]"; - { - no strict 'refs'; - if (defined (&$sub)) { - $currentstring = &$sub($target,$token,\@parstack); - $finaloutput .= $currentstring; - $currentstring = ''; - } else { - $finaloutput .= $token->[4]; - } - use strict 'refs'; + $result = ''; + } else { + $finaloutput .= $result; + } + if ($token->[0] eq 'E') { pop @stack;pop @parstack;&decreasedepth($token);} + } + pop @pars; + pop @Apache::lonxml::pwd; + } + + return $finaloutput; +} + +sub recurse { + + my @innerstack = (); + my @innerparstack = (); + my ($newarg,$target,$safeeval,$style_for_target,@parstack) = @_; + my @pat = (); + &newparser(\@pat,\$newarg); + my $tokenpat; + my $partstring = ''; + my $output=''; + my $decls=''; + while ( $#pat > -1 ) { + while ($tokenpat = $pat[$#pat]->get_token) { + if ($tokenpat->[0] eq 'T') { + if ($Apache::lonxml::textredirection == 1) {$partstring = $tokenpat->[1];} + } elsif ($tokenpat->[0] eq 'S') { + push (@innerstack,$tokenpat->[1]); + push (@innerparstack,&parstring($tokenpat)); + &increasedepth($tokenpat); + $partstring = &callsub("start_$tokenpat->[1]", + $target, $tokenpat, \@innerparstack, + \@pat, $safeeval, $style_for_target); + } elsif ($tokenpat->[0] eq 'E') { + #clear out any tags that didn't end + while ($tokenpat->[1] ne $innerstack[$#innerstack] + && ($#innerstack > -1)) { + &Apache::lonxml::error("Unbalanced tags in resource $innerstack['-1']"); + pop @innerstack;pop @innerparstack;&decreasedepth($tokenpat); } - } - } elsif ($token->[0] eq 'E') { -# Put here check for correct final tag (to avoid existence of starting tag only) - - pop @stack; - unless (exists $style_for_target{$token->[1]}) { - my $sub="end_$token->[1]"; - { - no strict 'refs'; - if (defined (&$sub)) { - $currentstring = &$sub($target,$token,\@parstack); - $finaloutput .= $currentstring; - $currentstring = ''; + $partstring = &callsub("end_$tokenpat->[1]", + $target, $tokenpat, \@innerparstack, + \@pat, $safeeval, $style_for_target); + } + #pass both the variable to the style tag, and the tag we + #are processing inside the + if ( $partstring ne "" ) { + if ( $#parstack > -1 ) { + if ( $#innerparstack > -1 ) { + $decls= $parstack[$#parstack].$innerparstack[$#innerparstack]; } else { - $finaloutput .= $token->[4]; + $decls= $parstack[$#parstack]; } - use strict 'refs'; - } - } -#-------------------------------------------------- end tag from the style file - if (exists $style_for_target{'/'."$token->[1]"}) { - $newarg = $style_for_target{'/'."$token->[1]"}; - if (index($newarg,'script') != -1 ) { - my $pat = HTML::TokeParser->new(\$newarg); - my $tokenpat; - my $partstring = ''; - my $oustring = ''; - my $outputstring; - - while ($tokenpat = $pat->get_token) { - if ($tokenpat->[0] eq 'T') { - $oustring .= $tokenpat->[1]; - } elsif ($tokenpat->[0] eq 'S') { - if ($tokenpat->[1] eq 'script') { - while ($tokenpat = $pat->get_token and $tokenpat->[1] ne 'script') { - if ($tokenpat->[0] eq 'S') { - $partstring .= $tokenpat->[4]; - } elsif ($tokenpat->[0] eq 'T') { - $partstring .= $tokenpat->[1]; - } elsif ($tokenpat->[0] eq 'E') { - $partstring .= $tokenpat->[2]; - } - } - - my @tempor_list = split(',',$parstack[$#parstack]); - my @te_kl = (); - my %tempor_hash = (); - map {(my $onete,my $twote) = split('=',$_); push (@te_kl,$onete); - $tempor_hash{$onete} = $twote} @tempor_list; - map {$partstring =~ s/\$$_/$tempor_hash{$_}/g; } @te_kl; - - &run($partstring,$safeeval); - - $partstring = ''; - } elsif ($tokenpat->[1] eq 'evaluate') { - $outputstring = &evaluate($tokenpat->[2]{expression},$safeeval); - $oustring .= $outputstring; - } else { - $oustring .= $tokenpat->[4]; - } - } elsif ($tokenpat->[0] eq 'E' and $tokenpat->[1] ne 'evaluate') { - $oustring .= $tokenpat->[1]; + } else { + if ( $#innerparstack > -1 ) { + $decls=$innerparstack[$#innerparstack]; + } else { + $decls=''; } - } - $newarg = $oustring; - } else { - my @very_temp = split(',',@parstack[$#parstack]); - map {my @ret= split('=',$_); $newarg =~ s/\$$ret[0]/$ret[1]/g; } @very_temp; - } + } + $output .= &Apache::run::evaluate($partstring,$safeeval,$decls); + $partstring = ''; + } + if ($tokenpat->[0] eq 'E') { pop @innerstack;pop @innerparstack; + &decreasedepth($tokenpat);} + } + pop @pat; + pop @Apache::lonxml::pwd; + } + return $output; +} - $finaloutput .= $newarg; - } - pop @parstack; +sub callsub { + my ($sub,$target,$token,$parstack,$parser,$safeeval,$style)=@_; + my $currentstring=''; + { + my $sub1; + no strict 'refs'; + if (my $space=$Apache::lonxml::alltags{$token->[1]}) { + #&Apache::lonxml::debug("Calling sub $sub in $space
\n"); + $sub1="$space\:\:$sub"; + $Apache::lonxml::curdepth=join('_',@Apache::lonxml::depthcounter); + $currentstring = &$sub1($target,$token,$parstack,$parser, + $safeeval,$style); + } else { + #&Apache::lonxml::debug("NOT Calling sub $sub in $space
\n"); + if (defined($token->[4])) { + $currentstring = $token->[4]; + } else { + $currentstring = $token->[2]; + } + } + use strict 'refs'; + } + return $currentstring; +} + +sub initdepth { + @Apache::lonxml::depthcounter=(); + $Apache::lonxml::depth=-1; + $Apache::lonxml::olddepth=-1; +} + +sub increasedepth { + my ($token) = @_; + $Apache::lonxml::depth++; + $Apache::lonxml::depthcounter[$Apache::lonxml::depth]++; + if ($Apache::lonxml::depthcounter[$Apache::lonxml::depth]==1) { + $Apache::lonxml::olddepth=$Apache::lonxml::depth; } + my $curdepth=join('_',@Apache::lonxml::depthcounter); + &Apache::lonxml::debug("s $Apache::lonxml::depth : $Apache::lonxml::olddepth : $curdepth : $token->[1]\n"); +#print "
s $Apache::lonxml::depth : $Apache::lonxml::olddepth : $curdepth : $token->[1]\n"; +} + +sub decreasedepth { + my ($token) = @_; + $Apache::lonxml::depth--; + if ($Apache::lonxml::depth<$Apache::lonxml::olddepth-1) { + $#Apache::lonxml::depthcounter--; + $Apache::lonxml::olddepth=$Apache::lonxml::depth+1; + } + if ( $Apache::lonxml::depth < -1) { + &Apache::lonxml::error("Unbalanced tags in resource"); + $Apache::lonxml::depth='-1'; + } + my $curdepth=join('_',@Apache::lonxml::depthcounter); + &Apache::lonxml::debug("e $Apache::lonxml::depth : $Apache::lonxml::olddepth : $token->[1] : $curdepth\n"); +#print "
e $Apache::lonxml::depth : $Apache::lonxml::olddepth : $token->[1] : $curdepth\n"; +} + +sub get_all_text { + + my($tag,$pars)= @_; + my $depth=0; + my $token; + my $result=''; + my $tag=substr($tag,1); #strip the / off the tag +# &Apache::lonxml::debug("have:$tag:"); + while (($depth >=0) && ($token = $pars->get_token)) { + if ($token->[0] eq 'T') { + $result.=$token->[1]; + } elsif ($token->[0] eq 'S') { + if ($token->[1] eq $tag) { $depth++; } + $result.=$token->[4]; + } elsif ($token->[0] eq 'E') { + if ( $token->[1] eq $tag) { $depth--; } + #skip sending back the last end tag + if ($depth > -1) { $result.=$token->[2]; } else { + $pars->unget_token($token); + } + } } - return $finaloutput; + return $result +} + +sub newparser { + my ($parser,$contentref,$dir) = @_; + push (@$parser,HTML::TokeParser->new($contentref)); + if ( $dir eq '' ) { + push (@Apache::lonxml::pwd, $Apache::lonxml::pwd[$#Apache::lonxml::pwd]); + } else { + push (@Apache::lonxml::pwd, $dir); + } +# &Apache::lonxml::debug("pwd:$#Apache::lonxml::pwd"); +# &Apache::lonxml::debug("pwd:$Apache::lonxml::pwd[$#Apache::lonxml::pwd]"); +} + +sub parstring { + my ($token) = @_; + my $temp=''; + map { + unless ($_=~/\W/) { + my $val=$token->[2]->{$_}; + if ($val =~ m/^[\%\@]/) { $val="\\".$val; } + $temp .= "my \$$_=\"$val\";" + } + } @{$token->[3]}; + return $temp; +} + +sub writeallows { + my $thisurl='/res/'.&Apache::lonnet::declutter(shift); + my $thisdir=$thisurl; + $thisdir=~s/\/[^\/]+$//; + my %httpref=(); + map { + $httpref{'httpref.'. + &Apache::lonnet::hreflocation($thisdir,$_)}=$thisurl; } @extlinks; + &Apache::lonnet::appenv(%httpref); +} + +sub handler { + my $request=shift; + + my $target='web'; +# $Apache::lonxml::debug=1; + if ($ENV{'browser.mathml'}) { + $request->content_type('text/xml'); + } else { + $request->content_type('text/html'); + } + +# $request->print(< +# +#Just test +# +# +#ENDHEADER +# &Apache::lonhomework::send_header($request); + $request->send_http_header; + + return OK if $request->header_only; + + $request->print(&Apache::lontexconvert::header()); + + $request->print(''."\n"); + + my $file = "/home/httpd/html".$request->uri; + my %mystyle; + my $result = ''; + $result = Apache::lonxml::xmlparse($target, &Apache::lonnet::getfile($file),'',%mystyle); + $request->print($result); + + $request->print(''); + $request->print(&Apache::lontexconvert::footer()); + writeallows($request->uri); + return OK; +} + +$Apache::lonxml::debug=0; +sub debug { + if ($Apache::lonxml::debug eq 1) { + print "DEBUG:".$_[0]."
\n"; + } +} +sub error { +# print "ERROR:".$_[0]."
\n"; +} +sub warning { + if ($Apache::lonxml::debug eq 1) { + print "WARNING:".$_[0]."
\n"; + } } 1; __END__ + + + + + + + + + + + + + + + + + + 500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.