WIRIS quizzes web services Getting started with PHP and Java Document Release: 1 2010 december, Maths for More www.wiris.com Summary This document provides client examples for PHP and Java. Contents WIRIS quizzes web services. Getting started with PHP and Java...2 Getting started with PHP...2 Random question example...5 Getting started using Java and Axis2...7 Building a simple client...7
2010, Maths for More WIRIS quizzes in your assessment system. V1 2 WIRIS quizzes web services. Getting started with PHP and Java The WIRIS quizzes services have two invocation protocols: SOAP and REST. The invocation of the REST service is exemplified with two PHP scripts. The SOAP version is explained using Java and the Axis 2 library. The examples of this appendix explain how to call the WIRIS quizzes Web services. The first PHP example and the Java example compare whether two expressions are equivalent. This is the common scenario when the input of the student has to be tested against a valid response in a quiz. The second PHP script uses a WIRIS CAS to exemplify the generation of random questions. Getting started with PHP In the following example, we will make a sample client in PHP for the WIRIS quizzes API web service. The example is written to not use any extension library. This demonstration example can be downloaded from http://www.wiris.com/portal/en/quizzes/docs/generic It is a zip file labeled PHP examples. It consists in two PHP files. Just take them and copy the file to some place accessible from your PHP interpreter. They will output an HTML file with the result of the test. Now we are interested in the first and simpler one, quizzes-api-client.php. This script uses the service to check whether two MathML strings are the same mathematical value or not. Let s see the code and how it works: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <title>wiris quizzes API PHP test</title> </head> <body> <?php //define the hypotetic correct answer and the student's answer. $mathml1 = '<mrow><mfrac><msqrt><mn>2</mn></msqrt><mn>2</mn></mfrac></mrow>'; $mathml2 = '<mrow><mfrac><mn>1</mn><msqrt><mn>2</mn></msqrt></mfrac></mrow>'; //build the input message $message = getequivsymbolicassertionmessage($mathml1, $mathml2); //call the service $result = callwirisapi($message); //get the interesting return value $value = getreturnvalue($result); //print the result echo '<h1>wiris quizzes API test</h1>'; echo 'mathml1 = '.htmlentities($mathml1).'<br />'; echo 'mathml2 = '.htmlentities($mathml2).'<br />'; echo '<strong>'; echo intval($value) == 1?'Are equivalent':'are not equivalent'; echo '</strong>';
2010, Maths for More WIRIS quizzes in your assessment system. V1 3 This is the entry point of the example. After defining the HTML headers, we define a pair of MathML strings. Then we call getequivsymbolicassertionmessage in order to build the XML input message. With that input message, we call the service (callwirisapi), and get the result also as an XML string. We use another function to get the interesting value from the result string (getreturnvalue). Finally, we output some html depending on the result. function getequivsymbolicassertionmessage($mathml1, $mathml2){ $assertion_name = 'equiv_symbolic'; $operation_name = 'getcheckassertions'; $mathml1 = wrapincdata($mathml1); $mathml2 = wrapincdata($mathml2); $xml = '<doprocessquestions>'. '<processquestions>'. '<processquestion>'. '<question>'. '<correctanswers>'. '<correctanswer type="mathml">'. $mathml1. '</correctanswer>'. '</correctanswers>'. '<assertions>'. '<assertion name="'.$assertion_name.'" />'. '</assertions>'. '</question>'. '<userdata>'. '<answers>'. '<answer type="mathml">'. $mathml2. '</answer>'. '</answers>'. '</userdata>'. '<processes>'. '<'.$operation_name.'/>'. '</processes>'. '</processquestion>'. '</processquestions>'. '</doprocessquestions>'; return $xml; This function builds the input message. We set the first MathML string to be the correct answer, the second MathML to be the user s answer and we define an assertion of type equiv_symbolic. This assertion compares the symbolical (mathematic) equivalence between the correct and the user s answers. Finally, we add the operation getcheckassertions that will output the result of the evaluation of the assertion.
2010, Maths for More WIRIS quizzes in your assessment system. V1 4 function callwirisapi($xml) { $url = 'http://services.wiris.com/quizzes/rest'; $opts = array( 'http' => array( 'method' => 'POST', 'header' => 'Content-type: text/xml; charset=utf-8'."\n". 'Content-Length: '.strlen($xml)."\n", 'content'=> $xml ) ); $context = stream_context_create($opts); $result = file_get_contents($url, false, $context); return $result; This function calls the service via http and the POST method. function wrapincdata($str) { return '<![CDATA['.$str.']]>'; function getreturnvalue($xml){ //in a more general purpose client the xml should be completely parsed, //here we go directly to the result. $pattern = '/<check[^>]*>(\d+)<\/check>/'; $matches = array(); preg_match($pattern, $xml, $matches); return $matches[1];?> </body> </html> This last function uses a regular expression to get the result. It will be the string 0 or 1. In a real scenario, is fully recommended to parse the whole XML message, but here it is enough to do it in this way. Of course this example doesn t cover the full potential of WIRIS quizzes API, and for a real application there will be needed to deal with XML not as a string but as a complex structure. Furthermore, such functions will be enclosed in a class or a file, and never embedded in an HTML. However, the important concepts are here and one can use that to start the development of the first prototype. For a more detailed specification of the service, see the reference http://www.wiris.com/portal/en/quizzes/docs/generic and the formal specification in the WSDL file http://services.wiris.com/quizzes/soap?wsdl.
2010, Maths for More WIRIS quizzes in your assessment system. V1 5 Random question example So far we have merely test the service. Now we make a complete example of the integration of WIRIS quizzes to make a random question. In order to make random questions, is necessary to have an algorithm to produce these random elements. The following is the simplest meaningful and complete example of a random question. Consider the other script quizzes-api-demo.php. The source will not be printed here, because of his length, and because is very close to the previous one. Thus, open it with a text / PHP editor and follow the workflow explained here in the code. Get it in your browser from your web server or from http://www.wiris.com/demo-php/quizzes/quizzes-apidemo.php and it will display: This is a minimal editing page for a random short answer question. In the first field we define the question statement. The variables are referenced with the sharp symbol # and the name This is a choice of the question engine. The second field is where we put the name of the variable holding the correct answer. Finally, we define the algorithm that produces the random items. Note that the program is enclosed in a library box. In order to embed a WIRIS CAS applet in a web page it is necessary to write an applet tag in the HTML. It admits a parameter for the initial session. There must be a pair of JavaScript lines to obtain the applet content. See the source code for more details. Clicking the submit button, the service will be called to get the value of the variables in order to compile the question text.
2010, Maths for More WIRIS quizzes in your assessment system. V1 6 By filling the answer field and clicking the submit button, the service is called again. Now we ask for the equivalence between the user s response and the correct answer. There are a few comments concerning these two calls: The question section in the input message is exactly the same. Indeed, it has been designed to have all the static data of the question, so it will be the same in all calls related to the same question. The randomseed element in the userdata section must be the same in the first and the second call, in order to have the same values when displaying the question and when grading. It should be different between attempts. Finally, we will get the result: Although this is a more complete example than the first, there also remain some features of the service that should be used in a real question engine: There are other and more powerful ways to grade the answer: one alternative way is to use function defined by the author in the WIRIS CAS applet (See the reference document). It is also possible to use other assertions than equiv_symbolic, and they can be combined (See http://services.wiris.com/assertions.xml for an updated list). So far we have used only plain text, but the interface can be much more powerful adding a WIRIS Editor in the answer field and displaying MathML formulas in the question text using the WIRIS Image Service. When this is done, it is worth to handle the syntax errors of the students when they write formulas. (See the Error section of the reference document).
2010, Maths for More WIRIS quizzes in your assessment system. V1 7 Getting started using Java and Axis2 In this document we will quickly build a simple SOAP client in the Java programming language for the WIRIS quizzes web services. This example gives the same functionality than the first. A compiled version of this example can be found at http://www.wiris.com/portal/en/quizzes/docs/generic It is a zip file labeled Java Examples. This example requires Java and that the Axis2 library is installed (see below). To run the example, unzip the file and execute in the command line of the system: java -classpath ".;%AXIS2_HOME%/lib/*" com.wiris.services.quizzes.wsdl.client Axis 2 is a helper library that will do all the dirty work of serializing the messages, connecting to the server, etc. Information about Axis 2 can be found at http://axis.apache.org/axis2/java/core/. Building a simple client This section explains how to implement a Java client using the Axis 2 library. The first step is to download (http://apache.rediris.es/axis/axis2/java/core/1.5.2/axis2-1.5.2-bin.zip) and install Axis2. For our purposes it is enough to unzip the file in any folder and define the environment variable AXIS2_HOME. Now, we are going to use the axis2 tool at bin/wsdl2java to build the so called stubs. These are the classes representing all the elements in the protocol: there will be a class for each different element in the specification of the protocol. The source is a WSDL file, located at http://services.wiris.com/quizzes/soap?wsdl. The command is: wsdl2java S src uri http://services.wiris.com/quizzes/soap?wsdl The first option is the folder where the java files have to be created. The second is the URI of the WSDL file. It should create a pair of files. The important one is the WirisQuizzesStub.java. This file contains as nested classes all the mentioned stubs, and also has two methods corresponding to the two operations provided by the service. Now let s write the client. Create a class called Client from where we will use WirisQuizzesStub in order to access the service with a concrete input. Consider the following commented code to understand how it works:
2010, Maths for More WIRIS quizzes in your assessment system. V1 8 package com.wiris.services.quizzes.wsdl; import java.rmi.remoteexception; import org.apache.axis2.axisfault; public class Client { /** * Test the "processquestions" remote method with an * assertion check. **/ public static void main(string[] argv){ Client c = new Client(); c.testserverinfo(); String mathml1 = "<mrow><mfrac><msqrt><mn>2</mn></msqrt><mn>2</mn></mfrac></mrow>"; String mathml2 = "<mrow><mfrac><mn>1</mn><msqrt><mn>2</mn></msqrt></mfrac></mrow>"; c.testequivsymbolic(mathml1,mathml2); This main method calls the two example functions. The first uses the dogetserverinfo operation to get some information about the server. It can be used to test the connectivity with the server. Then, it calls a second function that will test whether two MathML fragments represents the same value. /** * Test the "getserverinformation()" remote method **/ public void testserverinfo(){ try { WirisQuizzesStub wqs = new WirisQuizzesStub(); WirisQuizzesStub.DoGetServerInformationResponse response = wqs.dogetserverinformation(new WirisQuizzesStub.DoGetServerInformation()); System.out.println("Server info: "+response.getservername()+ " "+response.getversion()); catch (AxisFault e) { e.printstacktrace(); catch (RemoteException e) { e.printstacktrace(); Forgetting about the exception handling, this function is very simple. It calls the dogetserverinformation function of the service, with almost empty input. The returning object has two properties: servername and version. Now there is the second function commented below. public void testequivsymbolic(string mathml1, String mathml2) { try { WirisQuizzesStub.DoProcessQuestions dpq = new WirisQuizzesStub.DoProcessQuestions(); WirisQuizzesStub.ProcessQuestions pqs = new WirisQuizzesStub.ProcessQuestions(); dpq.setprocessquestions(pqs); WirisQuizzesStub.ProcessQuestion pq = new WirisQuizzesStub.ProcessQuestion();
2010, Maths for More WIRIS quizzes in your assessment system. V1 9 pqs.addprocessquestion(pq); WirisQuizzesStub.Question q = new WirisQuizzesStub.Question(); pq.setquestion(q); WirisQuizzesStub.CorrectAnswers cas = new WirisQuizzesStub.CorrectAnswers(); q.setcorrectanswers(cas); WirisQuizzesStub.CorrectAnswer ca = new WirisQuizzesStub.CorrectAnswer(); ca.setstring(mathml1); //1 ca.settype(wirisquizzesstub.mathtype.mathml); cas.addcorrectanswer(ca); WirisQuizzesStub.Assertions as = new WirisQuizzesStub.Assertions(); q.setassertions(as); WirisQuizzesStub.Assertion a = new WirisQuizzesStub.Assertion(); a.setname(wirisquizzesstub.assertionname.equiv_symbolic); //2 as.addassertion(a); WirisQuizzesStub.UserData u = new WirisQuizzesStub.UserData(); pq.setuserdata(u); WirisQuizzesStub.Answers ans = new WirisQuizzesStub.Answers(); u.setanswers(ans); WirisQuizzesStub.Answer an = new WirisQuizzesStub.Answer(); an.setstring(mathml2); //3 an.settype(wirisquizzesstub.mathtype.mathml); ans.addanswer(an); WirisQuizzesStub.Processes ps = new WirisQuizzesStub.Processes(); pq.setprocesses(ps); WirisQuizzesStub.ProcessesChoice pc = new WirisQuizzesStub.ProcessesChoice(); ps.addprocesseschoice(pc); pc.setgetcheckassertions(new WirisQuizzesStub.GetCheckAssertions()); //4 WirisQuizzesStub wqs = new WirisQuizzesStub(); //call process operation WirisQuizzesStub.DoProcessQuestionsResponse response = wqs.doprocessquestions(dpq); //5 WirisQuizzesStub.ProcessQuestionsResult pqsr = response.getprocessquestionsresult(); WirisQuizzesStub.ProcessQuestionResult pqr = pqsr.getprocessquestionresult()[0]; WirisQuizzesStub.GetCheckAssertionsResult gcar = pqr.getprocessquestionresultchoice()[0].getgetcheckassertionsresult(); WirisQuizzesStub.Check c = gcar.getcheck()[0]; //6 System.out.println("The result is: "+c.get_boolean()); catch (AxisFault e) { e.printstacktrace(); catch (RemoteException e) { e.printstacktrace(); We have to build the input message, constructing all the needed objects. The numbered lines are the interesting ones. 1. Set the first MathML string to be the correct answer.
2010, Maths for More WIRIS quizzes in your assessment system. V1 10 2. Define an assertion to be of type equiv_symbolic. This assertion checks whether the correct answer and the student s answer are mathematically equivalent. 3. Set the second MathML string to be the student s answer. 4. Add the operation getcheckassertions, i.e., evaluate the defined assertions. 5. Call the service. 6. Get the interesting return value. In these examples, we have seen that it is relatively easy to use this service. We only have used a very small part of the features of the service, so this is intended only to be a place where to start the not so trivial work of making a service client behind a question engine. For a more detailed specification of the service, see the reference http://www.wiris.com/portal/en/quizzes/docs/generic and the formal specification in the WSDL file http://services.wiris.com/quizzes/soap?wsdl.