You are here

function questions_import_qti_extract_info in Quiz 6.6

Same name and namespace in other branches
  1. 6.3 includes/questions_import/questions_import.admin.inc \questions_import_qti_extract_info()

Given a QTI 1.2 XML file, extract quiz questions.

1 call to questions_import_qti_extract_info()
questions_import_submit_qti12 in includes/questions_import/questions_import.admin.inc
This function imports questions from Question and Test Interoperability (QTI) format file.

File

includes/questions_import/questions_import.admin.inc, line 578
Administration file for Questions Import module

Code

function questions_import_qti_extract_info($file) {
  $items = array();
  foreach (qp($file, 'item') as $item) {
    $title = $item
      ->attr('title');
    $type = $item
      ->find('itemmetadata>qmd_itemtype')
      ->text();
    $body = $item
      ->end()
      ->find('presentation>material>mattext');
    if ($body
      ->attr('texttype') == 'text/html') {
      $bodytext = $body
        ->text();
      if (strpos($bodytext, '<html') === FALSE) {
        drupal_set_message('Adding HTML', 'status');
        $bodytext = '<html>' . $bodytext . '</html>';
      }

      // Load here so that errors are caught by Drupal (which has no exception handler.)
      $doc = new DOMDocument();
      $doc
        ->loadHTML($bodytext);
      $html = qp($doc, 'body');
      $contents = $html
        ->get(0)->childNodes;

      // Extract content from HTML and put it in a temp document.
      $newdoc = qp('<?xml version="1.0"?><div id="qti-question-body"/>');
      $i = 0;
      while ($node = $contents
        ->item($i++)) {
        $newdoc
          ->append($node);
      }
      $out = $newdoc
        ->html();

      // This leaves off XML declaration.
    }
    else {
      $out = $body
        ->text();
    }
    $new_item = array(
      'title' => $title,
      'type' => $type,
      'content' => $out,
    );

    // Handle multiple choice questions:
    if (strtolower($type) == 'multiple choice') {
      $answers = array();

      // First, get all anssers and loop through them.
      $answerstexts = $item
        ->parent('item')
        ->find('response_lid>render_choice>response_label>material>mattext');
      foreach ($answerstexts as $answertext) {

        // As we find each answer, grab a bunch of related data. Processing-wise, this is not terribly
        // efficient, since we are hoping back and forth inside of the document. However, it is much easier
        // to do this all together.
        $text = $answertext
          ->text();
        $index = $answertext
          ->parent('response_label')
          ->attr('ident');

        // This filter grabs the answer setting by index. Most of the time, index appears to be
        // an alpha char.
        $contains_filter = 'resprocessing>respcondition>conditionvar>varequal:contains(' . $index . ')';
        $correct = $answertext
          ->parent('item')
          ->find($contains_filter)
          ->parent('respcondition')
          ->find('setvar')
          ->text();
        if ($correct == 0) {
          $feedback = $answertext
            ->parent('item')
            ->find('itemfeedback[ident="Wrong Answer"]>material>mattext')
            ->text();
        }
        else {
          $feedback = 'Correct';
        }

        // Store all of this in an array.
        $answers[] = array(
          'text' => $text,
          'index' => $index,
          'is_correct' => $correct,
          'feedback' => $feedback,
        );
      }

      // Store answers
      $new_item['answers'] = $answers;
    }

    // Store questions
    $items[] = $new_item;
  }
  return $items;
}