--- loncom/xml/lonxml.pm 2001/06/13 20:02:28 1.93
+++ loncom/xml/lonxml.pm 2012/04/16 19:46:14 1.530
@@ -1,52 +1,130 @@
# The LearningOnline Network with CAPA
# XML Parser Module
#
-# last modified 06/26/00 by Alexander Sakharuk
-# 11/6 Gerd Kortemeyer
-# 6/1/1 Gerd Kortemeyer
-# 2/21,3/13 Guy
-# 3/29,5/4 Gerd Kortemeyer
-# 5/10 Scott Harrison
-# 5/26 Gerd Kortemeyer
-# 5/27 H. K. Ng
-# 6/2,6/3,6/8,6/9 Gerd Kortemeyer
-# 6/12,6/13 H. K. Ng
+# $Id: lonxml.pm,v 1.530 2012/04/16 19:46:14 raeburn Exp $
+#
+# Copyright Michigan State University Board of Trustees
+#
+# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
+#
+# LON-CAPA is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# LON-CAPA is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with LON-CAPA; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# /home/httpd/html/adm/gpl.txt
+#
+# http://www.lon-capa.org/
+#
+# Copyright for TtHfunc and TtMfunc by Ian Hutchinson.
+# TtHfunc and TtMfunc (the "Code") may be compiled and linked into
+# binary executable programs or libraries distributed by the
+# Michigan State University (the "Licensee"), but any binaries so
+# distributed are hereby licensed only for use in the context
+# of a program or computational system for which the Licensee is the
+# primary author or distributor, and which performs substantial
+# additional tasks beyond the translation of (La)TeX into HTML.
+# The C source of the Code may not be distributed by the Licensee
+# 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);
+qw(@pwd @outputstack $redirection $import @extlinks $metamode $evaluate %insertlist @namespace $errorcount $warningcount);
use strict;
-use HTML::TokeParser;
-use Safe;
-use Safe::Hole;
-use Math::Cephes qw(:trigs :hypers :bessels erf erfc);
-use Math::Random qw(:all);
-use Opcode;
+use LONCAPA;
+use HTML::LCParser();
+use HTML::TreeBuilder();
+use HTML::Entities();
+use Safe();
+use Safe::Hole();
+use Math::Cephes();
+use Math::Random();
+use Opcode();
+use POSIX qw(strftime);
+use Time::HiRes qw( gettimeofday tv_interval );
+use Symbol();
sub register {
- my $space;
- my @taglist;
- my $temptag;
- ($space,@taglist) = @_;
- foreach $temptag (@taglist) {
- $Apache::lonxml::alltags{$temptag}=$space;
+ my ($space,@taglist) = @_;
+ foreach my $temptag (@taglist) {
+ push(@{ $Apache::lonxml::alltags{$temptag} },$space);
+ }
+}
+
+sub deregister {
+ my ($space,@taglist) = @_;
+ foreach my $temptag (@taglist) {
+ my $tempspace = $Apache::lonxml::alltags{$temptag}[-1];
+ if ($tempspace eq $space) {
+ pop(@{ $Apache::lonxml::alltags{$temptag} });
+ }
}
+ #&printalltags();
}
use Apache::Constants qw(:common);
-use Apache::lontexconvert;
-use Apache::style;
-use Apache::run;
-use Apache::londefdef;
-use Apache::scripttag;
-use Apache::edit;
+use Apache::lontexconvert();
+use Apache::style();
+use Apache::run();
+use Apache::londefdef();
+use Apache::scripttag();
+use Apache::languagetags();
+use Apache::edit();
+use Apache::inputtags();
+use Apache::outputtags();
use Apache::lonnet;
-use Apache::File;
+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
+$warningcount=0;
+$errorcount=0;
+
#path to the directory containing the file currently being processed
@pwd=();
@@ -69,185 +147,136 @@ $evaluate = 1;
# data structure for eidt mode, determines what tags can go into what other tags
%insertlist=();
-#stores the list of active tag namespaces
+# stores the list of active tag namespaces
@namespace=();
-sub xmlbegin {
- my $output='';
- if ($ENV{'browser.mathml'}) {
- $output=''
- .''
- .']>'
- .'';
- } else {
- $output='';
- }
- return $output;
-}
+# stores all Scrit Vars displays for later showing
+my @script_var_displays=();
-sub xmlend {
- return '';
-}
+# a pointer the the Apache request object
+$Apache::lonxml::request='';
-sub fontsettings() {
- my $headerstring='';
- if (($ENV{'browser.os'} eq 'mac') && (!$ENV{'browser.mathml'})) {
- $headerstring.=
- '';
- }
- return $headerstring;
-}
-
-sub registerurl {
- if ($ENV{'REQUEST_URI'}!~/^\/(res\/)*adm\//) {
- my $hwkadd='';
- if ($ENV{'REQUEST_URI'}=~/\.(problem|exam|quiz|assess|survey|form)$/) {
- if (&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {
- $hwkadd.=(<
-// BEGIN LON-CAPA Internal
-
- function LONCAPAreg() {
- menu=window.open("","LONCAPAmenu");
- menu.clearTimeout(menu.menucltim);
- menu.currentURL=window.location.pathname;
- menu.currentStale=0;
- menu.clearbut(3,1);
- menu.switchbutton
- (8,1,'eval.gif','evaluate','this','gopost("/adm/evaluate",currentURL)');
- menu.switchbutton
- (8,2,'fdbk.gif','feedback','on this','gopost("/adm/feedback",currentURL)');
- menu.switchbutton
- (8,3,'prt.gif','prepare','printout','gopost("/adm/printout",currentURL)');
- menu.switchbutton
- (2,1,'back.gif','backward','','gopost("/adm/flip","back:"+currentURL)');
- menu.switchbutton
- (2,3,'forw.gif','forward','','gopost("/adm/flip","forward:"+currentURL)');
- $hwkadd
- }
-
- function LONCAPAstale() {
- menu=window.open("","LONCAPAmenu");
- menu.currentStale=1;
- menu.switchbutton
- (3,1,'reload.gif','return','location','go(currentURL)');
- menu.clearbut(7,1);
- menu.clearbut(7,2);
- menu.clearbut(7,3);
- menu.menucltim=menu.setTimeout(
- 'clearbut(2,1);clearbut(2,3);clearbut(8,1);clearbut(8,2);clearbut(8,3);',
- 2000);
+# a problem number counter, and check on ether it is used
+$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.
-// END LON-CAPA Internal
-
-ENDREGTHIS
- } else {
- return (<
-// BEGIN LON-CAPA Internal
+#internal check on whether to look at style defs
+$Apache::lonxml::usestyle=1;
- function LONCAPAreg() {
- menu=window.open("","LONCAPAmenu");
- menu.currentStale=1;
- menu.clearbut(2,1);
- menu.clearbut(2,3);
- menu.clearbut(8,1);
- menu.clearbut(8,2);
- menu.clearbut(8,3);
- if (menu.currentURL) {
- menu.switchbutton
- (3,1,'reload.gif','return','location','go(currentURL)');
- } else {
- menu.clearbut(3,1);
- }
- }
+#locations used to store the parameter string for style substitutions
+$Apache::lonxml::style_values='';
+$Apache::lonxml::style_end_values='';
- function LONCAPAstale() {
- }
+#array of ssi calls that need to occur after we are done parsing
+@Apache::lonxml::ssi_info=();
-// END LON-CAPA Internal
-
-ENDDONOTREGTHIS
+#should we do the postag variable interpolation
+$Apache::lonxml::post_evaluate=1;
- }
-}
+#a header message to emit in the case of any generated warning or errors
+$Apache::lonxml::warnings_error_header='';
+
+# Control whether or not LaTeX symbols should be substituted for their
+# \ style equivalents...this may be turned off e.g. in an verbatim
+# environment.
-sub loadevents() {
- return 'LONCAPAreg();';
+$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 unloadevents() {
- return 'LONCAPAstale();';
+sub xmlend {
+ my ($target,$parser)=@_;
+ my $mode='xml';
+ my $status='OPEN';
+ if ($Apache::lonhomework::parsing_a_problem ||
+ $Apache::lonhomework::parsing_a_task ) {
+ $mode='problem';
+ $status=$Apache::inputtags::status[-1];
+ }
+ 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 '';
+ }
+
+ return $discussion;
}
sub printalltags {
my $temp;
foreach $temp (sort keys %Apache::lonxml::alltags) {
- &Apache::lonxml::debug("$temp -- $Apache::lonxml::alltags{$temp}");
+ &Apache::lonxml::debug("$temp -- ".
+ join(',',@{ $Apache::lonxml::alltags{$temp} }));
}
}
sub xmlparse {
- my ($target,$content_file_string,$safeinit,%style_for_target) = @_;
- if ($target eq 'meta') {
- $Apache::lonxml::redirection = 0;
- $Apache::lonxml::metamode = 1;
- $Apache::lonxml::evaluate = 1;
- $Apache::lonxml::import = 0;
- } elsif ($target eq 'grade') {
- &startredirection;
- $Apache::lonxml::metamode = 0;
- $Apache::lonxml::evaluate = 1;
- $Apache::lonxml::import = 1;
- } elsif ($target eq 'modified') {
- $Apache::lonxml::redirection = 0;
- $Apache::lonxml::metamode = 0;
- $Apache::lonxml::evaluate = 0;
- $Apache::lonxml::import = 0;
- } else {
- $Apache::lonxml::redirection = 0;
- $Apache::lonxml::metamode = 0;
- $Apache::lonxml::evaluate = 1;
- $Apache::lonxml::import = 1;
+ my ($request,$target,$content_file_string,$safeinit,%style_for_target) = @_;
+
+ &setup_globals($request,$target);
+ &Apache::inputtags::initialize_inputtags();
+ &Apache::bridgetask::initialize_bridgetask();
+ &Apache::outputtags::initialize_outputtags();
+ &Apache::edit::initialize_edit();
+ &Apache::londefdef::initialize_londefdef();
+
+#
+# do we have a course style file?
+#
+
+ if ($env{'request.course.id'} && $env{'request.state'} ne 'construct') {
+ my $bodytext=
+ $env{'course.'.$env{'request.course.id'}.'.default_xml_style'};
+ if ($bodytext) {
+ 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));
+ }
}
- #&printalltags();
+#&printalltags();
my @pars = ();
- @Apache::lonxml::pwd=();
- my $pwd=$ENV{'request.filename'};
+ my $pwd=$env{'request.filename'};
$pwd =~ s:/[^/]*$::;
&newparser(\@pars,\$content_file_string,$pwd);
- my $currentstring = '';
- my $finaloutput = '';
- my $newarg = '';
- my $result;
my $safeeval = new Safe;
my $safehole = new Safe::Hole;
@@ -256,160 +285,216 @@ sub xmlparse {
($target, my @tenta) = split('&&',$target);
- my @stack = ();
+ my @stack = ();
my @parstack = ();
- &initdepth;
- my $token;
- while ( $#pars > -1 ) {
- while ($token = $pars[$#pars]->get_token) {
- if (($token->[0] eq 'T') || ($token->[0] eq 'C') || ($token->[0] eq 'D') ) {
- if ($metamode<1) { $result=$token->[1]; }
- } elsif ($token->[0] eq 'PI') {
- if ($metamode<1) { $result=$token->[2]; }
- } elsif ($token->[0] eq 'S') {
- # 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) {
- $Apache::lonxml::outputstack['-1'] .=
- &recurse($style_for_target{$token->[1]},$target,$safeeval,
- \%style_for_target,@parstack);
- } else {
- $finaloutput .= &recurse($style_for_target{$token->[1]},$target,
- $safeeval,\%style_for_target,@parstack);
- }
- } else {
- $result = &callsub("start_$token->[1]", $target, $token, \@stack,
- \@parstack, \@pars, $safeeval, \%style_for_target);
- }
- } elsif ($token->[0] eq 'E') {
- #clear out any tags that didn't end
- while ($token->[1] ne $stack[$#stack] && ($#stack > -1)) {
- &Apache::lonxml::warning("Unbalanced tags in resource $stack['-1']");
- pop @stack;pop @parstack;&decreasedepth($token);
- }
-
- if (exists $style_for_target{'/'."$token->[1]"}) {
- if ($Apache::lonxml::redirection) {
- $Apache::lonxml::outputstack['-1'] .=
- &recurse($style_for_target{'/'."$token->[1]"},
- $target,$safeeval,\%style_for_target,@parstack);
- } else {
- $finaloutput .= &recurse($style_for_target{'/'."$token->[1]"},
- $target,$safeeval,\%style_for_target,
- @parstack);
- }
-
- } else {
- $result = &callsub("end_$token->[1]", $target, $token, \@stack,
- \@parstack, \@pars,$safeeval, \%style_for_target);
- }
- } else {
- &Apache::lonxml::error("Unknown token event :$token->[0]:$token->[1]:");
- }
- #evaluate variable refs in result
- if ($result ne "") {
- if ( $#parstack > -1 ) {
- if ($Apache::lonxml::redirection) {
- $Apache::lonxml::outputstack['-1'] .=
- &Apache::run::evaluate($result,$safeeval,$parstack[$#parstack]);
- } else {
- $finaloutput .= &Apache::run::evaluate($result,$safeeval,
- $parstack[$#parstack]);
- }
- } else {
- $finaloutput .= &Apache::run::evaluate($result,$safeeval,'');
- }
- $result = '';
- }
- if ($token->[0] eq 'E') {
- pop @stack;pop @parstack;&decreasedepth($token);
- }
- }
- pop @pars;
- pop @Apache::lonxml::pwd;
+ &initdepth();
+ &init_alarm();
+ my $finaloutput = &inner_xmlparse($target,\@stack,\@parstack,\@pars,
+ $safeeval,\%style_for_target,1);
+
+ 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() }
-# if ($target eq 'meta') {
-# $finaloutput.=&endredirection;
-# }
-
- if (($ENV{'QUERY_STRING'}) && ($target eq 'web')) {
- $finaloutput=&afterburn($finaloutput);
- }
+ &clean_safespace($safeeval);
+ if (@script_var_displays) {
+ my $scriptoutput = join('',@script_var_displays);
+ $finaloutput=~s{(\s*