--- loncom/xml/lonxml.pm 2002/09/10 20:53:36 1.194
+++ loncom/xml/lonxml.pm 2013/10/29 21:01:21 1.544
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# XML Parser Module
#
-# $Id: lonxml.pm,v 1.194 2002/09/10 20:53:36 www Exp $
+# $Id: lonxml.pm,v 1.544 2013/10/29 21:01:21 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -36,32 +36,32 @@
# The C source of the Code may not be distributed by the Licensee
# to any other parties under any circumstances.
#
-# 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
-# 6/16 Gerd Kortemeyer
-# 7/27 H. K. Ng
-# 8/7,8/9,8/10,8/11,8/15,8/16,8/17,8/18,8/20,8/23,8/24 Gerd Kortemeyer
-# Guy Albertelli
-# 9/26 Gerd Kortemeyer
-# Dec Guy Albertelli
-# YEAR=2002
-# 1/1 Gerd Kortemeyer
-# 1/2 Matthew Hall
-# 1/3 Gerd Kortemeyer
-#
+
+=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 $prevent_entity_encode);
+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();
@@ -70,6 +70,9 @@ 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,@taglist) = @_;
@@ -95,15 +98,33 @@ use Apache::style();
use Apache::run();
use Apache::londefdef();
use Apache::scripttag();
+use Apache::languagetags();
use Apache::edit();
-use Apache::lonnet();
+use Apache::inputtags();
+use Apache::outputtags();
+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
+$warningcount=0;
+$errorcount=0;
+
#path to the directory containing the file currently being processed
@pwd=();
@@ -129,352 +150,82 @@ $evaluate = 1;
# stores the list of active tag namespaces
@namespace=();
-# if 0 all high ASCII characters will be encoded into HTML Entities
-$prevent_entity_encode=0;
-
-# 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='';
-sub xmlbegin {
- my $output='';
- if ($ENV{'browser.mathml'}) {
- $output=''
- .''
- .']>'
- .'';
- } else {
- $output='';
- }
- return $output;
-}
+# a problem number counter, and check on ether it is used
+$Apache::lonxml::counter=1;
+$Apache::lonxml::counter_changed=0;
-sub xmlend {
- my ($discussiononly,$symb)=@_;
- my $discussion='';
- if ($ENV{'request.course.id'}) {
- my $crs='/'.$ENV{'request.course.id'};
- if ($ENV{'request.course.sec'}) {
- $crs.='_'.$ENV{'request.course.sec'};
- }
- $crs=~s/\_/\//g;
- my $seeid=&Apache::lonnet::allowed('rin',$crs);
- unless ($symb) {
- $symb=&Apache::lonnet::symbread();
- }
- if ($symb) {
- my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
- $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
- $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
- if ($contrib{'version'}) {
- unless ($discussiononly) {
- $discussion.=
- '
';
- }
- my $idx;
- for ($idx=1;$idx<=$contrib{'version'};$idx++) {
- my $hidden=($contrib{'hidden'}=~/\.$idx\./);
- unless (($hidden) && (!$seeid)) {
- my $message=$contrib{$idx.':message'};
- $message=~s/\n/\
/g;
- $message=&Apache::lontexconvert::msgtexconverted($message);
- if ($message) {
- if ($hidden) {
- $message=''.$message.'';
- }
- my $sender='Anonymous';
- if ((!$contrib{$idx.':anonymous'}) || ($seeid)) {
- $sender=&Apache::loncommon::aboutmewrapper(
- $contrib{$idx.':plainname'},
- $contrib{$idx.':sendername'},
- $contrib{$idx.':senderdomain'}).' ('.
- $contrib{$idx.':sendername'}.' at '.
- $contrib{$idx.':senderdomain'}.')';
- if ($contrib{$idx.':anonymous'}) {
- $sender.=' [anonymous] '.
- $contrib{$idx.':screenname'};
- }
- if ($seeid) {
- if ($hidden) {
- $sender.=' Make Visible';
- } else {
- $sender.=' Hide';
- }
- }
- } else {
- if ($contrib{$idx.':screenname'}) {
- $sender=''.$contrib{$idx.':screenname'}.'';
- }
- }
- $discussion.=''.$sender.' ('.
- localtime($contrib{$idx.':timestamp'}).
- '):
'.$message.
- '
';
- }
- }
- }
- unless ($discussiononly) {
- $discussion.='';
- }
- }
- if ($discussiononly) {
- $discussion.=''.$symb.'
';
- }
- }
- }
- return $discussion.($discussiononly?'':'');
-}
+# 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.
-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='';
- }
-
-
-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
- ''.
- 'Checked out for '.$plainname.
- '
User: '.$tuname.' at '.$tudom.
- '
ID: '.$idhash{$tuname}.
- '
CourseID: '.$tcrsid.
- '
Course: '.$ENV{'course.'.$tcrsid.'.description'}.
- '
DocID: '.$token.
- '
Time: '.localtime().'
';
- } else {
- return $token;
- }
-}
+%Apache::lonxml::counters_per_part = ();
-sub fontsettings() {
- my $headerstring='';
- if (($ENV{'browser.os'} eq 'mac') && (!$ENV{'browser.mathml'})) {
- $headerstring.=
- '';
- }
- return $headerstring;
-}
-
-sub registerurl {
- my $forcereg=shift;
- my $target = shift;
- my $result = '';
- if ($target eq 'edit') {
- $result .="\n";
- }
- if ((($ENV{'request.publicaccess'}) ||
- (!&Apache::lonnet::is_on_map($ENV{'REQUEST_URI'}))) &&
- (!$forcereg)) {
- return $result.
- '';
- }
- if ($Apache::lonxml::registered && !$forcereg) { return ''; }
- $Apache::lonxml::registered=1;
- my $nothing='';
- if ($ENV{'browser.type'} eq 'explorer') { $nothing='javascript:void(0);'; }
- my $timesync='menu.syncclock(1000*'.time.');';
- if (($ENV{'REQUEST_URI'}!~/^\/(res\/)*adm\//) || ($forcereg)) {
- my $hwkadd='';
- if ($ENV{'request.filename'}=~/\.(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("$nothing","LONCAPAmenu","",false);
- menu.clearTimeout(menu.menucltim);
- $timesync
- menu.currentURL=window.location.pathname;
- menu.reloadURL=window.location.pathname;
- menu.currentStale=0;
- menu.clearbut(3,1);
- menu.switchbutton
- (6,3,'catalog.gif','catalog','info','catalog_info()');
- menu.switchbutton
- (8,1,'eval.gif','evaluate','this','gopost("/adm/evaluate",currentURL)');
- menu.switchbutton
- (8,2,'fdbk.gif','feedback','discuss','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)');
- menu.switchbutton
- (9,1,'sbkm.gif','set','bookmark','set_bookmark()');
- menu.switchbutton
- (9,2,'vbkm.gif','view','bookmark','edit_bookmarks()');
- menu.switchbutton
- (9,3,'anot.gif','anno-','tations','annotate()');
- $hwkadd
- }
-
- function LONCAPAstale() {
- menu=window.open("$nothing","LONCAPAmenu","",false);
- menu.currentStale=1;
- if (menu.reloadURL!='' && menu.reloadURL!= null) {
- menu.switchbutton
- (3,1,'reload.gif','return','location','go(reloadURL)');
- }
- 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);'+
- 'clearbut(9,1);clearbut(9,2);clearbut(9,3);clearbut(6,3)',
- 2000);
+#internal check on whether to look at style defs
+$Apache::lonxml::usestyle=1;
- }
+#locations used to store the parameter string for style substitutions
+$Apache::lonxml::style_values='';
+$Apache::lonxml::style_end_values='';
-// END LON-CAPA Internal
-
-ENDREGTHIS
+#array of ssi calls that need to occur after we are done parsing
+@Apache::lonxml::ssi_info=();
- } else {
- $result = (<
-// BEGIN LON-CAPA Internal
+#a header message to emit in the case of any generated warning or errors
+$Apache::lonxml::warnings_error_header='';
- function LONCAPAreg() {
- menu=window.open("$nothing","LONCAPAmenu","",false);
- $timesync
- 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);
- }
- }
+# Control whether or not LaTeX symbols should be substituted for their
+# \ style equivalents...this may be turned off e.g. in an verbatim
+# environment.
- function LONCAPAstale() {
- }
+$Apache::lonxml::substitute_LaTeX_symbols = 1; # Starts out on.
-// END LON-CAPA Internal
-
-ENDDONOTREGTHIS
- }
- return $result;
+sub enable_LaTeX_substitutions {
+ $Apache::lonxml::substitute_LaTeX_symbols = 1;
}
-
-sub loadevents() {
- return 'LONCAPAreg();';
+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 {
@@ -489,26 +240,41 @@ sub xmlparse {
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'}) {
+ 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));
- }
- }
+ 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 = ();
- my $pwd=$ENV{'request.filename'};
+ my $pwd=$env{'request.filename'};
$pwd =~ s:/[^/]*$::;
&newparser(\@pars,\$content_file_string,$pwd);
@@ -521,71 +287,103 @@ sub xmlparse {
my @stack = ();
my @parstack = ();
- &initdepth;
-
+ &initdepth();
+ &init_alarm();
my $finaloutput = &inner_xmlparse($target,\@stack,\@parstack,\@pars,
- $safeeval,\%style_for_target);
- if ($ENV{'request.uri'}) {
- &writeallows($ENV{'request.uri'});
- }
- 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,' ');
+ $safeeval,\%style_for_target,1);
- $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;
- }
+ 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() }
- $tree = $tree->delete;
+ &clean_safespace($safeeval);
- return $output;
+ if (@script_var_displays) {
+ my $scriptoutput = join('',@script_var_displays);
+ $finaloutput=~s{(\s*