Maths with QTI – QTI XML Basic Structure

Please note that this is a work in progress!

This is the first of my QTI XML Building Blocks posts, where I will give the basic structure of an assessment item in a QTI XML file, that can be used as a framework that can be filled in with the building blocks that I will cover in future posts. This is very much a work in progress and I can’t promise everything is correct. At this stage I am just trying to create something that is useful to me, and putting it out there in case it is useful to anyone else!

So, here is the basic structure of a QTI XML document (or the basic structure I’ve been using/copying for writing questions):

<?xml version="1.0" encoding="UTF-8"?>

<!-- Define question properties -->
<!-- Some of these are obvious, others are XML namespace definitions - not all of these are generally needed 
   adaptive - if set to false, only one attempt is allowed, so this is best for summative items. If set to true, multiple attempts are allowed and the feedback/outcomes can be changed, and this is better for formative items, where a user can have multiple goes. This should not be confused with an adaptive test, where the questions presented change depending on a user's answers to previous questions, although a similar thing can be achieved within an adaptive item.
-->
<assessmentItem xmlns="http://www.imsglobal.org/xsd/imsqti_v2p1"
   xmlns:m="http://www.w3.org/1998/Math/MathML"
   xmlns:xi="http://www.w3.org/2001/XInclude"
   xmlns:xlink="http://www.w3.org/1999/xlink"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:ma="http://mathassess.qtitools.org/xsd/mathassess"
   xsi:schemaLocation="http://www.imsglobal.org/xsd/imsqti_v2p1 imsqti_v2p1.xsd http://mathassess.qtitools.org/xsd/mathassess mathassess.xsd">
   xml:lang="en"
   adaptive="true"
   timeDependent="false"
   identifier="questionidentifier"
   title="Question Title">

   <!-- VARIABLE DECLARATIONS -->
   <!-- Here we define all of the variables that are going to be used in the question -->

   <!-- Response Declarations -->
   <!-- These are the variables used in response processing, including those for storing the response(s) given by the user -->
   <responseDeclaration identifier="RESPONSE" cardinality="single" baseType="integer"/>

   <!-- Outcome Declarations -->
   <!-- These are the variables used for returning an outcome to the user, e.g. score, feedback -->
   <outcomeDeclaration identifier="SCORE" cardinality="single" baseType="integer"/>

   <!-- Template Declarations -->
   <!-- These are the variables used for creating the question, e.g. the variables used for randomising values within a question -->
   <templateDeclaration identifier="iA" cardinality="single" baseType="integer" mathVariable="true"/>

   <!-- TEMPLATE PROCESSING -->
   <templateProcessing>
      <!-- Here template variables are assigned values, constraints are defined etc -->
   </templateProcessing>

   <!-- ITEM BODY -->
   <itemBody>
      <!-- The itemBody contains the content of the item, including the question, interactions, feedback sections (which are initially hidden) etc  -->
   </itemBody>

   <!-- RESPONSE PROCESSING -->
   <responseProcessing>
      <!-- Here the user's response is assessed, compared the correct answer etc, and outcome variable, e.g. score and which feedback to show, are set -->
   </responseProcessing>
</assessmentItem>

Maths with QTI – Help Guide for Maths Entry Questions

This is intended as a simple guide to entering mathematical expressions as answers to questions delivered using QTIWorks. Any comments about its usefulness/helpfulness would be most welcome.

Note that you can also view an input hints box by clicking on the blue question mark symbol help_questionmark next to the maths input box. You can also watch a brief video showing you how to enter mathematical answers.

This guide contains the following sections:

The Maths Input box ^ Top

When a mathematical expression is required as an answer to a question, a text box within a larger grey box is shown. When text is typed into the text box, it is interpreted mathematically, and the resulting mathematical expression is shown:

mathsinputbox_mod

If you click on the blue question mark symbol help_questionmark, an input hints box will pop up.

Basic Operators (+ – * / =) ^ Top

The basic mathematical operators can be represented by words or symbols, as shown in the table below.

Operation Symbol Word
Addition +
Subtraction
Multiplication * times
Division / divide
Equals =

note that multiplication is implied between a coefficient and a variable, e.g. 2x = 2*x, and between consecutive variables, i.e. letters, unless the letters make up a special character, e.g. pa = p*a, but pi = π, not p*i.

Other Operators (± > ≥ < ≤ ≠) ^ Top

Other operatores, e.g. comparison operators, can be represented as shown in the table below.

Operation Input Interpretation
Plus or minus +- ±
Greater than > >
Greater than or equal to >=
Less than < <
Less than or equal to <=
Not equal !=

Precedence (order of operations) ^ Top

The order of precedence, i.e. the order in which operations are performed/interpreted, follows the usual rules:

  1. brackets
  2. roots and exponentials
  3. multiplication and division
  4. addition and subtraction
Input Interpretation Notes
2+3*4 precedence_nobrackets equals 14
2+(3*4) precedence_unnecessarybrackets equals 14, brackets are unnecessary
(2+3)*4 precedence_brackets equals 20, brackets are required

Special Symbols and Functions ^ Top

Generally, letters just represent variables, and multiplication between consecutive letters is implied (see Basic Operations above). However, there are certain letters or words that have special meaning, as follows:

Letter/Word Meaning
e e, the natural exponential, 2.71828…
i the imaginary number, √-1
alpha…lambda…pi…etc Greek letters, α, λ, π etc
log logarithm function
ln natural logarithm function
sin, cos, tan trigonometric functions
cap, cup, in, not, notin, subset, subseteq, to,
vee, wedge…and probably others
Logic and Set Theory operators

Fractions (a/b) ^ Top

Use the divide symbol,  ‘/’, between the numerator (top) denominator (bottom) of a fraction. Brackets may be needed to give the correct numerator and denominator.

Input Interpretation
1/2 half
2x+1/3x+2 fraction_no_brackets
(2x+1)/(3x+2) fraction_brackets

Brackets (a(b+c)) ^ Top

Brackets can be used as they normally would when writing an expression.

Input Interpretation Notes
sin(2x+30)  brackets_sin  brackets not needed for sin of single value, e.g. sinx gives sinx
5(x+1)(2x-3)  brackets_2
3(2x-(2-y))  brackets_nested equivalent to 3(2x-2+y)

Powers (x^a) ^ Top

Use ^ (hat/caret symbol) to represent powers:

Input Interpretation Notes
x^2 powers_xsquared    
x^(1/3) powers_xtothird fractional powers need brackets
x^-1 powers_xtominus1 negative powers do not need brackets
e^(x(2x+1)) powers_expbrackets
e^x(2x+1) powers_expnobrackets

Roots (sqrt(x) or x^(a/b)) ^ Top

Only a square root can be represented with the root symbol. All other roots must be represented as fractional powers:

Root Input Interpretation
Square root (√x) sqrtx or sqrt(x) roots_sqrtx
Cube root (∛x) x^(1/3) roots_cubertx

Subscripts (x_a) ^ Top

Use _ (underscore) to give a subscript (similar to using ^ for powers/superscripts)

Input Interpretation
x_1 subscript_x_1
y_a subscript_y_a

“Sorry, I could not make sense of your input” ^ Top

You will see this message in a number of situations (including, but not limited to):

  • When you have an operator (e.g. + – * / ^ _ =), that does not have a value/variable before and/or after it, e.g. ‘1+’, ‘*3’, ‘x/’, ‘y^’
  • When you have two consecutive operators, e.g. ‘+*’
  • When you have opened a bracket and not (yet) closed it, e.g. ‘2(x+3’

If you see this message when you believe you have entered a complete expression, make sure you check your expression carefully, in particular that you have closed all brackets.

WordPress: Improvement to Form Manager plugin when used with Members plugin

As mentioned in my earlier post, the WordPress Form Manager and Member’s plugins integrate fantastically. However, one thing that didn’t quite perfectly was that if a user was allowed to view the submission data for forms (the ‘

This is because, by default, clicking on the name of a form takes you to the edit/design page, whether or not you are allowed to edit the form. Therefore, if you are not allowed to edit the form, it doesn’t show the page, and you see nothing except the tabs for the actions that you are allowed to access, in this case the “Submission Data” tab. To see the submission data, you then have to click on this tab to view the data. Obviously, this second click is annoying, and the blank page is ugly/confusing.

Thankfully, this issue was quite easy to fix, by replacing line 155 of wordpress-form-manager/pages/main.php with the following code:

<strong>
   <?php if(!$fm_MEMBERS_EXISTS || current_user_can('form_manager_forms') || current_user_can('form_manager_data')) { ?>
      <a class="row-title" href="<?php
      //If the user can edit forms, take them to the edit page, as usual
      if(!$fm_MEMBERS_EXISTS || current_user_can('form_manager_forms')) { 
         echo get_admin_url(null, 'admin.php')."?page=fm-edit-form&sec=design&id=".$form['ID'];
      }
      //Otherwise, if the user can view the data, take them to the data page
      else if(current_user_can('form_manager_data')) { 
         echo get_admin_url(null, 'admin.php')."?page=fm-edit-form&sec=data&id=".$form['ID'];
      }
   ?>"><?php echo $form['title'];?></a>
   <?php } 
   //If user has no form permissions, do not create a link
   else { 
      echo $form['title']; 
   }  ?>
</strong>

Basically this just means that:

  • If the Members plugin isn’t installed, the link goes to the edit/design page
  • If the user can edit forms, the link goes to the edit/design page
  • If the user can’t edit forms but can view data, the link goes to the submission data page
  • If the user can’t edit forms or view data (i.e. they can do nothing with individual forms), then the form name isn’t made into a link

I hope this is a robust improvement – it seems to work well for me, and will prevent my ‘view data only’ users from getting annoyed/confused by the form link taking them to the wrong place.

WordPress Form Manager and Members plugins integrate brilliantly

We’ve been working with the WordPress Form Manager plugin for a while, and have found it an excellent and flexible way to create forms in WordPress (thanks Campbell Hoffman). However, I was initially struggling when trying to change the way the permissions worked within the plugin.

By default, only site administrators get to see the forms menu item in the Dashboard, and only they can edit forms, view submission data etc. I wanted to allow other roles (e.g. Contributors) to view submission data, but, ideally, not to edit forms, change advanced form settings etc, or edit posts etc. Therefore, I started looking around in the Form Manager plugin code to see if I could change things to allow different roles to do different things and was getting confused by things like the $fm_MEMBERS_EXISTS variable. What I should have done, as always, is look at the docs for the plugin, where I would have found (and eventually did find) this: http://www.campbellhoffman.com/form-manager-faq/#how-do-i-restrict-access-to-different-parts-of-form-manager-members

It turns out that the Form Manager plugin integrates with Justin Tadlock’s Member’s plugin, which in itself seems like an excellent plugin, allowing you to change the capabilities associated with different roles, create your own roles and more. As an aside, users, roles and capabilities in WordPress can be confusing, but Justin’s post on the what they all mean makes it much less so.

Therefore, combining these two plugins allowed me to create a new role that has very limited capabilities. Alongside the standard ‘read’ capability, all they can do is view the list of available forms (the ‘form_manager_main’ capability), view the submission data table (‘

In conclusion, I would say the Members plugin is a ‘must have’ if you want something other than the standard roles offered by WordPress and the Form Manager plugin, of which I was already a fan, is made all the better thanks to its ability to integrate with Members.

Changing site in WordPress Multisite (e.g. for getting posts from other sites)

I’ve been playing around with WordPress Multisite, and (in some custom plugin code) wanted to be able to get posts from and save posts to a different site to the one that I was in. Thankfully, there are a couple of functions that make this very easy:

switch_to_blog( $id )

restore_current_blog()

What these do is probably fairly self explanatory, but if you give switch_to_blog() the id of a blog, it will switch to that blog. Calling restore_current_blog() with then switch back to the original blog.

For example, to save a post to the current blog, and another blog, you can do the following:

//Post data
$newPost = array(
   'post_title' => 'title',
   'post_content' => 'content',
   'post_status' =>  'publish',
   'post_author' => $userId,
   'post_category' => 'category
);

$postID = wp_insert_post($newPost, false); //Insert post into current blog

switch_to_blog( $otherBlogID ); //Switch to the other blog

$otherPostID = wp_insert_post($newPost, false); //Insert post into other blog

restore_current_blog(); //Switch back to the current blog

CSS hacks (underscore and star) for old IE versions

Ideally it shouldn’t be necessary to provide different CSS for different browsers, but sometimes needs must, particularly when it comes to dealing with the quirks of older versions of Internet Explorer (i.e. IE6 and IE7).

Thankfully there’s a couple of simple hacks that can be used to target CSS at old versions of IE only – the underscore (_) hack for IE6 (and below) and the star (*) hack for IE7 (and below). Just put _ or * in front of a CSS property as required, e.g.:

color: red;   /* all browsers */
*color: blue;   /* IE7 and below */
_color: green;   /* IE6 and below */

Using these rules, this sentence should appear green in IE6 and below, blue in IE7 and red in all other browsers.

There are other hacks that can be used. Check out these blog posts for more:

CSS Tip: Targeting IE 5.x, 6 and 7 Separately

IE7 only CSS hacks: Explained

Adding an image to a child theme template (e.g. header/footer) in WordPress

Child themes in WordPress are great, because they allow you to modify a theme without making changes to the theme’s core code, which makes things much easier when the theme gets updated – you don’t have to redo all of your changes.

I wanted to add an image to a custom footer template in a child theme (created by copying footer.php from the parent theme). I’d created an images directory in my child theme and put my image there, but was struggling to generate the correct link to the image.

After a bit of searching, I found this suggestion:

<img src="<?php echo get_template_directory_uri(); ?>/images/image.jpg" />

However, this was pointing to the image directory in the parent theme, not the child theme. Further searching led me to this blog: How to load files within WordPress themes, which had the answer (and explains things in more detail):

<img src="<?php echo get_stylesheet_directory_uri(); ?>/images/image.jpg" />

The basic difference, when using a child theme, is this:

  • Template refers to the parent theme
  • Stylesheet refers to the child theme

More information on the get_stylesheet_directory_uri() function can be found here: http://codex.wordpress.org/Function_Reference/get_stylesheet_directory_uri

Note: an alternative is to use the bloginfo() function (echo is not needed), as follows:

<img src="<?php bloginfo('stylesheet_directory'); ?>/images/image.jpg" />

However, it turns out that this is just an indirect way of calling get_stylesheet_directory_uri(), via get_bloginfo() in wp-includes/general-template.php. Both are included in the codex, so I don’t think it really matters which you use.

Another note: Dropping the _uri from the end of the function (i.e. get_stylesheet_directory()), will return the absolute server path to your child theme stylesheet directory, which can be used for including a another php file, e.g.

<?php include( get_stylesheet_directory() . '/includes/myfile.php'); ?>

More on this here: http://codex.wordpress.org/Function_Reference/get_stylesheet_directory

jsTree: different contextmenu actions for different nodes

jsTree is a great jQuery plugin for easily creating expandable trees, e.g. from a list of items. We use it in our personalised portal page for Weblearn – see Personalising WebLearn (Sakai) – to display document trees.

We have been working on increasingly the functionality of this portal page to allow students to easily upload files. To do this, we are making use of the ‘contextmenu’ functionality of jsTree, which allows you to specify a menu of actions that can be accessed by right clicking on a tree node.

One thing that wasn’t immediately obvious from the jsTree docs was how to show different actions depending on the type of node, e.g. file or folder, on which the user clicked. However, it turns out that this can be done quite easily, by passing the ‘items’ parameter of the contextmenu configuration a function (that returns an object), rather than an object, as follows:

$('#tree_container').jstree({ 
    "plugins" : [ "contextmenu" ],
    "contextmenu" : {
        "items" : customMenu
    }
});

You then need to set up the customMenu function to return an items object, for example:

function customMenu(node) {
   //Show a different label for renaming files and folders
   if ($(node).hasClass("jstree-closed") || $(node).hasClass("jstree-open")) { //If node is a folder
      var renameLabel = "Rename Folder";
   }
   else {
      var renameLabel = "Rename File";
   }
   var items = {
      "upload" : {
          "label" : "Upload File",
          "action" : function () { ... }
      },
      "rename" : {
         "label" : renameLabel,   //Different label (defined above) will be shown depending on node type
         "action" : function () { ... }
      },
      "delete" : {
         "label" : "Delete File",
         "action" : function () { ... }
      }
   };

   //If node is a folder do not show the "delete" menu item
   if ($(node).hasClass("jstree-closed") || $(node).hasClass("jstree-open")) {
      delete items.remove;
   }

   return items;
}

Copying Arrays (and Objects) in Javascript

This is a bit of an amateur mistake, but I definitely wasn’t the first person to make it and I suspect I won’t be the last. I had a JavaScript array that I wanted to copy, then make some change to the copy, so that I could access the original and the modified copy. Therefore, being used to PHP, I did the following, assuming it would make a ‘proper’ copy of the original:

var original = [1,2,3];  //Define original array
var copy = original;     //Attempt to copy original
copy[2] = 4;             //Modify the copy
alert(original[2]);      //Hoped for 3, got 4

I’d created a reference to the original array, rather than a copy of it. As a result, updating the copy also updated the original.

So, how do I create a copy of an array, rather than a reference. Thankfully, the slice method makes this very easy:

var original = [1,2,3];        //Define original array
var copy = original.slice(0);  //Copy original using slice
copy[2] = 4;                   //Modify the copy
alert(original[2]);            //Got 3 this time

This works fine for simple, one-dimensional arrays, where the array contains only booleans, numbers or strings. If the array is multi-dimensional, i.e. it contains other arrays or objects, then only the top level array will be copied, the arrays/objects it contains will be referenced. Therefore, it is necessary to create a function to do this – this seems to be a good way to do: http://my.opera.com/GreyWyvern/blog/show.dml/1725165

Alternatively, use jQuery, and take advantage of the extend method:

var original = {team:"Arsenal"};               //Define original object
var copy = jQuery.extend(true, {}, original);  //Copy original using extend
copy.team = "Man Utd" ;                        //Modify the copy
alert(original.team);                          //Alerts Arsenal

The Basics of writing a Basic LTI Tool Provider

I hope this will be helpful for anyone just getting started with (Basic) LTI and wanting to create their first Tool Provider. Apologies for any abuse/misuse of the terminology – this is just how I understand it. To recap the two halves of an LTI launch:

Tool Consumer (TC) = An LTI-enabled VLE/LMS/other system that can make an LTI launch request. Generally (or at least the way we are using it), the TC manages user accounts/passwords, so that the Tool Provider doesn’t have to.
Tool Provider (TP) = an external tool that receives an LTI request from a TC and uses the launch data to work out what the user is able to see/do within the tool.

Useful links

I found the following useful when getting to grips with LTI and creating my first TP (in PHP):

Thanks of course to Dr Chuck and the rest of the LTI community for developing this specification and the above Classes, Tools and Tutorials.

Basic Implementation

The PHP Basic LTI class makes it very easy to do the LTI/OAuth bit of the TP. Here’s my pseudo-PHP code for the basic process:

//All of the LTI Launch data gets passed through in $_REQUEST
if(isset($_REQUEST['lti_message_type'])) {    //Is this an LTI Request?

    //We store oauth_consumer_key and secret pairs in our database, so we look the secret up here, but it can just be hard-coded (especially for testing)
    $secret = [secret];

    //Get BLTI class to do all the hard work (more explanation of these below)
    // - first parameter is the secret, which is required
    // - second parameter (defaults to true) tells BLTI whether to store the launch data is stored in the session ($_SESSION['_basic_lti_context'])
    // - third parameter (defaults to true) tells BLTI whether to redirect the user after successful validation
    $context = new BLTI($secret, true, false);

    //Deal with results from BLTI class 
    if($context->complete) exit(); //True if redirect was done by BLTI class
    if($context->valid) { //True if LTI request was verified
     //Let the user in
    }
}
else { //Not an LTI request, so either don't let this user in, or provide another way for them to authenticate, or show them only public content
}

Just to further explain the parameters passed when instantiating the BLTI class, the first argument is the secret, which is required and would usually be a string. Alternatively, you can pass through an associative array of database information (e.g. ‘table’ => ‘lti_keys’, ‘key_column’ => ‘oauth_consumer_key’), and the BLTI class will look up the secret from the database.

The second argument (true by default) tells the BLTI class whether to store the launch data in the session (from which it can be retrieved using $_SESSION[‘_basic_lti_context’]) and whether to try to automatically retrieve any stored LTI launch data if someone tries to access a tool without coming in through LTI. This means that if a user has initially come to a tool through LTI, then closes the browser tab containing the tool, and then goes directly back to the tool, without coming through LTI, as long as their session has not expired they will be allowed back into the tool, even though have not come through LTI. I would generally recommend keeping this as true, as I think this would usually be useful behaviour.

The third argument (true by default, but I generally set it to false) tells the BLTI class whether to do the redirect or not after validation of the request. Setting this to false will prevent it from doing the redirect.

I hope this is helpful. My understanding is pretty (cheap pun alert!) basic, so I would welcome any thoughts, queries, suggestions or corrections.

For further information/discussion of LTI, and how we have used it to allow access to our iCases system through WebLearn (our VLE), please see these posts: