--- loncom/xml/lonxml.pm 2004/08/19 20:53:48 1.336 +++ loncom/xml/lonxml.pm 2023/11/28 02:39:01 1.566 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # XML Parser Module # -# $Id: lonxml.pm,v 1.336 2004/08/19 20:53:48 albertel Exp $ +# $Id: lonxml.pm,v 1.566 2023/11/28 02:39:01 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -37,11 +37,31 @@ # to any other parties under any circumstances. # +=pod + +=head1 NAME + +Apache::lonxml + +=head1 SYNOPSIS + +XML Parsing Module + +This is part of the LearningOnline Network with CAPA project +described at http://www.lon-capa.org. + + +=head1 SUBROUTINES + +=cut + + package Apache::lonxml; use vars -qw(@pwd @outputstack $redirection $import @extlinks $metamode $evaluate %insertlist @namespace $errorcount $warningcount @htmlareafields); +qw(@pwd @outputstack $redirection $import @extlinks $metamode $evaluate %insertlist @namespace $errorcount $warningcount); use strict; +use LONCAPA; use HTML::LCParser(); use HTML::TreeBuilder(); use HTML::Entities(); @@ -49,9 +69,12 @@ use Safe(); use Safe::Hole(); use Math::Cephes(); use Math::Random(); +use Math::Calculus::Expression(); +use Number::FormatEng(); use Opcode(); use POSIX qw(strftime); - +use Time::HiRes qw( gettimeofday tv_interval ); +use Symbol(); sub register { my ($space,@taglist) = @_; @@ -81,16 +104,23 @@ use Apache::languagetags(); use Apache::edit(); use Apache::inputtags(); use Apache::outputtags(); -use Apache::lonnet(); +use Apache::lonnet; use Apache::File(); use Apache::loncommon(); use Apache::lonfeedback(); use Apache::lonmsg(); use Apache::loncacc(); +use Apache::lonmaxima(); +use Apache::lonr(); use Apache::lonlocal; +use Apache::lonhtmlcommon(); +use Apache::functionplotresponse(); +use Apache::lonnavmaps(); + +#==================================== Main subroutine: xmlparse -#================================================== Main subroutine: xmlparse #debugging control, to turn on debugging modify the correct handler + $Apache::lonxml::debug=0; # keeps count of the number of warnings and errors generated in a parse @@ -116,14 +146,14 @@ $metamode = 0; # turns on and of run::evaluate actually derefencing var refs $evaluate = 1; -# data structure for eidt mode, determines what tags can go into what other tags +# data structure for edit mode, determines what tags can go into what other tags %insertlist=(); # stores the list of active tag namespaces @namespace=(); -# has the dynamic menu been updated to know about this resource -$Apache::lonxml::registered=0; +# stores all Scrit Vars displays for later showing +my @script_var_displays=(); # a pointer the the Apache request object $Apache::lonxml::request=''; @@ -132,6 +162,16 @@ $Apache::lonxml::request=''; $Apache::lonxml::counter=1; $Apache::lonxml::counter_changed=0; +# Part counter hash. In analysis mode, the +# problems can use this to record which parts increment the counter +# by how much. The counter subs will maintain this hash via +# their optional part parameters. Note that the assumption is that +# analysis is done in one request and therefore it is not necessary to +# save this information request-to-request. + + +%Apache::lonxml::counters_per_part = (); + #internal check on whether to look at style defs $Apache::lonxml::usestyle=1; @@ -148,159 +188,53 @@ $Apache::lonxml::post_evaluate=1; #a header message to emit in the case of any generated warning or errors $Apache::lonxml::warnings_error_header=''; -sub xmlbegin { - my $output=''; - @htmlareafields=(); - if ($ENV{'browser.mathml'}) { - $output='' - .'' - .']>' - .''; - } else { - $output=''; - } - return $output; +# Control whether or not LaTeX symbols should be substituted for their +# \ style equivalents...this may be turned off e.g. in an verbatim +# environment. + +$Apache::lonxml::substitute_LaTeX_symbols = 1; # Starts out on. + +sub enable_LaTeX_substitutions { + $Apache::lonxml::substitute_LaTeX_symbols = 1; +} +sub disable_LaTeX_substitutions { + $Apache::lonxml::substitute_LaTeX_symbols = 0; } sub xmlend { my ($target,$parser)=@_; my $mode='xml'; my $status='OPEN'; - if ($Apache::lonhomework::parsing_a_problem) { + if ($Apache::lonhomework::parsing_a_problem || + $Apache::lonhomework::parsing_a_task ) { $mode='problem'; $status=$Apache::inputtags::status[-1]; } - my $discussion=&Apache::lonfeedback::list_discussion($mode,$status); + my $discussion; + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, + ['LONCAPA_INTERNAL_no_discussion']); + if ( + ( (!exists($env{'form.LONCAPA_INTERNAL_no_discussion'})) + || ($env{'form.LONCAPA_INTERNAL_no_discussion'} ne 'true') + ) + && ($env{'form.inhibitmenu'} ne 'yes') + ) { + $discussion=&Apache::lonfeedback::list_discussion($mode,$status); + } if ($target eq 'tex') { $discussion.='\keephidden{ENDOFPROBLEM}\vskip 0.5mm\noindent\makebox[\textwidth/$number_of_columns][b]{\hrulefill}\end{document}'; &Apache::lonxml::newparser($parser,\$discussion,''); return ''; - } else { - return $discussion.''; - } -} - -sub tokeninputfield { - my $defhost=$Apache::lonnet::perlvar{'lonHostID'}; - $defhost=~tr/a-z/A-Z/; - return (< - function updatetoken() { - var comp=new Array; - var barcode=unescape(document.tokeninput.barcode.value); - comp=barcode.split('*'); - if (typeof(comp[0])!="undefined") { - document.tokeninput.codeone.value=comp[0]; - } - if (typeof(comp[1])!="undefined") { - document.tokeninput.codetwo.value=comp[1]; - } - if (typeof(comp[2])!="undefined") { - comp[2]=comp[2].toUpperCase(); - document.tokeninput.codethree.value=comp[2]; - } - document.tokeninput.barcode.value=''; - } - - - -DocID Checkin - - - -Scan in Barcode - - -or Type in DocID - - -* - -* - - - - - - - -ENDINPUTFIELD -} - -sub maketoken { - my ($symb,$tuname,$tudom,$tcrsid)=@_; - unless ($symb) { - $symb=&Apache::lonnet::symbread(); - } - unless ($tuname) { - $tuname=$ENV{'user.name'}; - $tudom=$ENV{'user.domain'}; - $tcrsid=$ENV{'request.course.id'}; - } - - return &Apache::lonnet::checkout($symb,$tuname,$tudom,$tcrsid); -} - -sub printtokenheader { - my ($target,$token,$tsymb,$tcrsid,$tudom,$tuname)=@_; - unless ($token) { return ''; } - - my ($symb,$courseid,$domain,$name) = &Apache::lonxml::whichuser(); - unless ($tsymb) { - $tsymb=$symb; - } - unless ($tuname) { - $tuname=$name; - $tudom=$domain; - $tcrsid=$courseid; - } - - my %reply=&Apache::lonnet::get('environment', - ['firstname','middlename','lastname','generation'], - $tudom,$tuname); - my $plainname=$reply{'firstname'}.' '. - $reply{'middlename'}.' '. - $reply{'lastname'}.' '. - $reply{'generation'}; - - if ($target eq 'web') { - my %idhash=&Apache::lonnet::idrget($tudom,($tuname)); - return - ''. - &mt('Checked out for').' '.$plainname. - ''.&mt('User').': '.$tuname.' at '.$tudom. - ''.&mt('ID').': '.$idhash{$tuname}. - ''.&mt('CourseID').': '.$tcrsid. - ''.&mt('Course').': '.$ENV{'course.'.$tcrsid.'.description'}. - ''.&mt('DocID').': '.$token. - ''.&mt('Time').': '.&Apache::lonlocal::locallocaltime().''; - } else { - return $token; } -} -sub fontsettings() { - my $headerstring=''; - if (($ENV{'browser.os'} eq 'mac') && (!$ENV{'browser.mathml'})) { - $headerstring.= - ''; - } elsif (!$ENV{'browser.mathml'} && $ENV{'browser.unicode'}) { - $headerstring.= - ''; - } - return $headerstring; + return $discussion; } sub printalltags { - my $temp; - foreach $temp (sort keys %Apache::lonxml::alltags) { - &Apache::lonxml::debug("$temp -- ". - join(',',@{ $Apache::lonxml::alltags{$temp} })); - } + foreach my $temp (sort(keys(%Apache::lonxml::alltags))) { + &Apache::lonxml::debug("$temp -- ". + join(',',@{ $Apache::lonxml::alltags{$temp} })); + } } sub xmlparse { @@ -308,6 +242,7 @@ sub xmlparse { &setup_globals($request,$target); &Apache::inputtags::initialize_inputtags(); + &Apache::bridgetask::initialize_bridgetask(); &Apache::outputtags::initialize_outputtags(); &Apache::edit::initialize_edit(); &Apache::londefdef::initialize_londefdef(); @@ -316,28 +251,31 @@ sub xmlparse { # do we have a course style file? # - if ($ENV{'request.course.id'} && $ENV{'request.state'} ne 'construct') { + if ($env{'request.course.id'} && $env{'request.state'} ne 'construct') { my $bodytext= - $ENV{'course.'.$ENV{'request.course.id'}.'.default_xml_style'}; + $env{'course.'.$env{'request.course.id'}.'.default_xml_style'}; if ($bodytext) { - my $location=&Apache::lonnet::filelocation('',$bodytext); - my $styletext=&Apache::lonnet::getfile($location); - if ($styletext ne '-1') { - %style_for_target = (%style_for_target, - &Apache::style::styleparser($target,$styletext)); - } - } - } elsif ($ENV{'construct.style'} && ($ENV{'request.state'} eq 'construct')) { - my $location=&Apache::lonnet::filelocation('',$ENV{'construct.style'}); + foreach my $file (split(',',$bodytext)) { + my $location=&Apache::lonnet::filelocation('',$file); + my $styletext=&Apache::lonnet::getfile($location); + if ($styletext ne '-1') { + %style_for_target = (%style_for_target, + &Apache::style::styleparser($target,$styletext)); + } + } + } + } elsif ($env{'construct.style'} + && ($env{'request.state'} eq 'construct')) { + my $location=&Apache::lonnet::filelocation('',$env{'construct.style'}); my $styletext=&Apache::lonnet::getfile($location); - if ($styletext ne '-1') { - %style_for_target = (%style_for_target, - &Apache::style::styleparser($target,$styletext)); - } + if ($styletext ne '-1') { + %style_for_target = (%style_for_target, + &Apache::style::styleparser($target,$styletext)); + } } #&printalltags(); my @pars = (); - my $pwd=$ENV{'request.filename'}; + my $pwd=$env{'request.filename'}; $pwd =~ s:/[^/]*$::; &newparser(\@pars,\$content_file_string,$pwd); @@ -350,64 +288,76 @@ sub xmlparse { my @stack = (); my @parstack = (); - &initdepth; - + &initdepth(); + &init_alarm(); my $finaloutput = &inner_xmlparse($target,\@stack,\@parstack,\@pars, - $safeeval,\%style_for_target); + $safeeval,\%style_for_target,1); - if ($ENV{'request.uri'}) { - &writeallows($ENV{'request.uri'}); + if (@stack) { + &warning(&mt('At end of file some tags were still left unclosed:'). + ' <'.join('>, <',reverse(@stack)). + '>'); + } + if ($env{'request.uri'}) { + &writeallows($env{'request.uri'}); } &do_registered_ssi(); if ($Apache::lonxml::counter_changed) { &store_counter() } - return $finaloutput; -} - -sub htmlclean { - my ($raw,$full)=@_; - - my $tree = HTML::TreeBuilder->new; - $tree->ignore_unknown(0); - $tree->parse($raw); - - my $output= $tree->as_HTML(undef,' '); - - $output=~s/\<(br|hr|img|meta|allow)(.*?)\>/\<$1$2 \/\>/gis; - $output=~s/\<\/(br|hr|img|meta|allow)\>//gis; - unless ($full) { - $output=~s/\<[\/]*(body|head|html)\>//gis; - } + &clean_safespace($safeeval); - $tree = $tree->delete; - - return $output; + if (@script_var_displays) { + if ($finaloutput =~ m{\s*