function wrsqz_extractTextFromMathML($formula, $encoded=true){ //Algorythm: We scan the mathML tag by tag. //If a tag is one of the allowed (math, mrow) we save it at the stack //and continue with the next. //If the tag is not allowed (mfenced, mfrac,...) we skip all mathML until its //closure (</mfenced>, </mfrac>) //If the tag is <mtext> we rearange the formula //If a tag is a closure of allowed tag, we pop it from the stack. //rapid return if nothing to do. if(strpos($formula,'mtext')===false) return $formula; //initializations $opentag = $encoded ? '«' : '<'; $closetag = $encoded ? '»' : '>'; //tags where an <mtext> can live inside. $allowedtags = array('math', 'mrow'); $pattern = $opentag.'([^'.$opentag.$closetag.']*)'.$closetag; //regexp that matches a single tag label mb_ereg_search_init($formula, $pattern); $stack = array(); //stack of opened tags $omittedcontent=false; //there is math content before the current point? $lasttag=null; //last tag of the stack $length = strlen($formula); $beginformula = strpos($formula, $opentag); //position of the first character of the last formula (in bytes). $pos=array(0,0); //CAUTION: If you change this function, be very carefull with multibyte // and non-multibyte functions. while(($pos[0]+$pos[1])<$length){ $pos = mb_ereg_search_pos($pattern); if($pos[0]+$pos[1] < $length){ //this will be always true but the last iteration mb_ereg_search_setpos($pos[0]+$pos[1]); } $tag = substr($formula, $pos[0],$pos[1]); $trimmedTag = mb_substr($tag,1,-1); //skip autoclosed tags if(mb_substr($trimmedTag,-1) == '/'){ continue; } //discard attributes if(($spacepos = mb_strpos($trimmedTag,' '))!==false){ $trimmedTag=mb_substr($trimmedTag,0,$spacepos); } if(in_array($trimmedTag,$allowedtags)){ //allowed tag $stack[]=array($trimmedTag,$tag); $lasttag = $trimmedTag; }else if($trimmedTag == '/'.$lasttag){ //close allowed tag array_pop($stack); $lasttag = end($stack); $lasttag = $lasttag[0]; //discard empty formulas if(empty($stack) && !$omittedcontent){ $formula1 = substr($formula, 0, $beginformula); if($pos[0]+$pos[1]<$length){ //this isn't the end. $formula2 = substr($formula, $pos[0]+$pos[1]); $formula = $formula1 . $formula2; $length = strlen($formula); mb_ereg_search_init($formula, $pattern); mb_ereg_search_setpos($beginformula); }else{ //this is the last iteration. $length and mb_ereg_search //string and position will be wrong, but it doesn't matter. $formula = $formula1; } } }else if($trimmedTag == 'mtext'){ $pos2 = mb_ereg_search_pos($opentag.'/mtext'.$closetag); $text = substr($formula, $pos[0]+$pos[1], $pos2[0]-($pos[0]+$pos[1])); //Decode some chars in text if($encoded) $text=wrsqz_mathmlDecode($text); $text = str_replace('·','·',$text); $text = str_replace(''',''',$text); $formula1 = substr($formula, 0, $pos[0]); //until <mtext> $formula2 = substr($formula, $pos2[0]+$pos2[1]); //from </mtext> if($omittedcontent){ //we have a non-empty formula before the text so we must close it //compute the tail (close tags) of the formula before the text //and the head (open tags) of the formula after the text. $copystack = $stack; //copy stack $tail1 = ''; $head2 = ''; while($stacktag = array_pop($copystack)){ $tail1.= $opentag.'/'.$stacktag[0].$closetag; $head2 = $stacktag[1] . $head2; } $formula1 = $formula1 . $tail1; $formula2 = $head2 . $formula2; //update $formula $formula = $formula1 . $text . $formula2; $beginformula = $pos[0]+strlen($tail1)+strlen($text); $position = $beginformula+strlen($head2); }else{ //we have an empty formula before the text so we must skip it. $head = substr($formula1, 0, $beginformula); //all before the empty formula $formula1 = substr($formula1, $beginformula); $formula = $head . $text . $formula1 . $formula2; $beginformula += strlen($text); $position = $beginformula +strlen($formula1); } //update parameters with the new formula. $length = strlen($formula); $omittedcontent = false; mb_ereg_search_init($formula, $pattern); mb_ereg_search_setpos($position); }else{ //not allowed tag: go to its closure and remember that we omitted content $pos = mb_ereg_search_pos($opentag.'/'.$trimmedTag.$closetag); if($pos === false){ return $formula; //this is an error in XML (unclosed tag); } $omittedcontent=true; mb_ereg_search_setpos($pos[0]+$pos[1]); } } return $formula; }
function wrsqz_import_from_xml($questionType, $dbType, &$data, &$question, &$format, &$extra) { if (isset($data['@']['type']) && $data['@']['type'] == $questionType . 'wiris') { $qfxml = new qformat_xml(); if ($questionType == 'essay') { $question = $qfxml->import_essay($data); }else if ($questionType == 'match') { $question = $qfxml->import_matching($data); }else if ($questionType == 'multichoice') { $question = $qfxml->import_multichoice($data); }else if ($questionType == 'truefalse') { $question = $qfxml->import_truefalse($data); }else if ($questionType == 'shortanswer') { $question = $qfxml->import_shortanswer($data); }else if ($questionType == 'multianswer') { $questiontext = $data['#']['wirisquestiontext'][0]['#']['text']; $container = new stdClass; $container->questiontext = $qfxml->import_text($questiontext); $question = wrsqz_qtype_multianswer_extract_question($container); $question->course = $qfxml->course; $question->generalfeedback = $qfxml->getpath($data, array('#','generalfeedback',0,'#','text',0,'#'), '', true ); $question->name = $qfxml->import_text( $data['#']['name'][0]['#']['text'] ); } unset($qfxml); $question->qtype = $questionType . 'wiris'; $program = wrsqz_mathmlDecode($format->getpath($data, array('#', 'wirisquestion', 0, '#'), 0)); $imported = wrsqz_importCASSession($program); if($imported===false) return false; $question->hiddenCASValue = $imported[0]; $translation = $imported[1]; if ($questionType == 'shortanswer') { mb_parse_str($format->getpath($data, array('#', 'wiriseditor', 0, '#'), 0), $eqoptionArray); $question->wirisEditor = (isset($eqoptionArray['editor']) && $eqoptionArray['editor'] == 'true') ? 'editor=true' : ''; $question->multipleAnswers = (isset($eqoptionArray['multipleAnswers']) && $eqoptionArray['multipleAnswers'] == 'true') ? 'multipleAnswers=true' : ''; $question->wirisCASForComputations = (isset($eqoptionArray['wirisCASForComputations']) && $eqoptionArray['wirisCASForComputations'] == 'true') ? 'wirisCASForComputations=true' : ''; if(isset($eqoptionArray['testFunctionName'])){ foreach ($eqoptionArray['testFunctionName'] as $index => $functionName){ if(!empty($functionName)){ $question->testFunctionName[$index]=$functionName; } } } }else if ($questionType == 'multichoice') { $question->gradeOverride = explode(';', $format->getpath($data, array('#', 'wirisoverrideanswer', 0, '#'), 0)); }else if ($questionType == 'truefalse') { $question->wirisAnswer = $format->getpath($data, array('#', 'wirisoverrideanswer', 0, '#'), 0); }else if ($questionType == 'multianswer'){ //mb_parse_str($format->getpath($data, array('#', 'wiriseditor', 0, '#'), 0), $eqoptionArray); //$question->wirisEditor = (isset($eqoptionArray['editor']) && $eqoptionArray['editor'] == 'true') ? 'editor=true' : ''; } $options = $format->getpath($data, array('#', 'wirisoptions',0,'#'), array()); $question->wirisCASForComputations = $format->getpath($options, array('wirisCASForComputations',0,'#'),0); //TODO: translate cas if needed. $question->hiddenInitialCASValue = wrsqz_mathmlDecode($format->getpath($options, array('hiddenInitialCASValue',0,'#'),0)); if(!empty($translation)){ wrsqz_replaceVarReferencesInFlatQuestion($questionType, $question, $translation); } return $question; } return false; }