Introduction
The idea to write an online quiz came up when I was looking for an XML tutorial. I visited W3Schools.com and found not only the tutorial I was looking for, but more interestingly was an online quiz. I took the 20-questions quiz once, and hey! I felt great about it. I wonder why there are just few web sites offering online quiz like that.
A quiz is a great way to test your knowledge. An online quiz is a great addition to your web site that could keep your visitors glued for a few more minutes.
Download the demo project and try it. It is a 10-question quiz to challenge your knowledge about Australian geography. Don't worry! All data is kept in a clear, human-readable XML document, so you could easily peek for answers.
The Script Explained
I will not go through a very detail discussion about the script, but rather highlight several areas in the script. Once you get the whole idea about the script, then it is easy to modify or extend the script to suit your requirements.
Recursive Script
There is only one aspx script to do various tasks in the online quiz. It is a recursive script: a script that 'calls' itself over and over again until a certain condition is reached. Precisely, the script does not call itself, but posts form data to itself. This process is known as post back.
As the script posts back to itself continuously over the duration of the quiz, we could say that it has many states. The first state is to initialize several essential variables, count the total question, and record the quiz start time. Then, in the first and each following state, the script displays a multiple choice question to challenge user (see the snapshot above). A user answering the question will trigger onClick
event, forcing a post-back, and move the script to the next state. In the next state, the script will run a subroutine associated with the event to check the answer and display the next multiple question. The recursive flow repeats again and again, until the last question is processed, where at this point a result is displayed.
The following activity diagram represents the recursive flow of the online quiz script.
Maintaining State
The online quiz script needs to maintain state of its variables. There are a bunch of alternatives to do so. The most advanced way is to use the session
object, and the conventional way is to use hidden inputs or a QueryString. ASP.NET introduces another alternative called 'state bag'. Unlike the session object, state bag is not persisted over the whole user session, but is brought forward from one page to another page just like hidden inputs and querystring. However, it is superior to hidden inputs and QueryStrings, since it can accept more data types and the content has been encoded into a single string and therefore is not easy to tamper with.
Storing value into state bag:
ViewState("TotalQuestion") = intTotalQuestion
Getting value from state bag:
intTotalQuestion = ViewState("TotalQuestion")
The following is a list of variables to be kept in the state bag:
Variable Name | State Bag Name | Data Type | Comments |
intTotalQuestion | TotalQuestion | int | Keeps the total question in the quiz. The value is populated in the first state of the quiz and remains constants over the duration of quiz. |
intScore | Score | int | Keeps the number of correct answer. |
intQuestionNo | QuestionNo | int | Holds the last question number the user attempted. |
arrAnswerHistory | AnswerHistory | arraylist of int | Records answers in the quiz. It will record 0 (zero) if the answer is correct, otherwise record the selectedindex of the radio buttons. |
(none) | CorrectAnswer | int | Holds the correct answer of previous question. It is made available in the next state when the answer is checked for correctness. |
(none) | StartTime | date | Holds the start time of the quiz. It is used to calculate the time spent in the quiz. |
XML Data
Data for the online quiz is kept in an XML document named quiz.xml, which is validated using an XML schema named quiz.xsd. A valid XML document consists of a root element called quiz
, which has at least one element called mchoice
(short for multiple-choice). Each mchoice
element has one question
child element, and two or more answer
child elements. The answer element may have the correct
attribute with possible value of either yes
or no
. In fact, you should supply the correct
attribute with a value of yes
to one of the answers in the same mchoice
, otherwise there will be no correct answer for the question.
quiz.xml:
<?xml version="1.0" encoding="UTF-8"?>
<quiz xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="quiz.xsd">
<mchoice>
<question>What is the capital city of Australia ?</question>
<answer>Sydney</answer>
<answer correct="yes">Canberra</answer>
<answer>Melbourne</answer>
<answer>Gold Coast</answer>
</mchoice>
<mchoice>
<question>Which city has an extensive tram network?</question>
<answer>Sydney</answer>
<answer correct="yes">Melbourne</answer>
<answer>Adelaide</answer>
<answer>Ballarat</answer>
</mchoice>
</quiz>
It is possible to insert HTML tags within the XML data, therefore the quiz may contain decorated texts, images, links, etc. instead of plain text. Just make sure to enclose the HTML tags with CDATA
block, so the XML document is still valid. Look at the following example:
<mchoice>
<question><![CDATA[Which of the following is <u>NOT</u>
Australian native animals?]]></question>
<answer>Kangaroo</answer>
<answer correct="yes">Penguin</answer>
<answer>Koala</answer>
<answer>Wombat</answer>
</mchoice>
quiz.xsd:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="quiz">
<xs:complexType>
<xs:choice>
<xs:element name="mchoice" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="question" type="xs:string"/>
<xs:element name="answer" minOccurs="2" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="correct" use="optional">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="yes"/>
<xs:enumeration value="no"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
The online quiz script does not validate the XML document against the XML Schema for several reasons. First, it is a resource intensive process, forcing XMLTextReader
to go through each element and attribute in the XML document. Second, we need to validate the XML document just once after it has been updated, instead of every time we load the file. To validate the XML document, you could write a separate aspx script or use a third-party tool and run them manually every after you finish updating the XML document.
XML Document Object Model
XML Document Object Model (DOM) is a tree-like structure that represents every node of an XML document based on the hierarchical relationship with its parent nodes and child nodes. The DOM allows us to navigate and manipulate XML document in more logical way.
To build an XML DOM, we use the XMLDocument
class. The XMLDocument class itself extends the XMLNode
class, therefore many of its properties and methods are inherited from XMLNode. While XMLNode's methods and properties apply to a specific node in an XML document, methods and properties of XMLDocument apply to the whole XML document.
The following code create an instance of XMLDocument and build XML DOM from quiz.xml:
Dim xDoc as XMLDocument = New XMLDocument()
xDoc.Load(Server.MapPath("quiz.xml"))
Addressing a specific node in the XML DOM is a bit tricky. We should navigate our 'pointer' through the DOM starting from its root node. The following code demonstrates how to address the first question of the first multiple choice:
Dim xNode as XMLNode
'Goto the first/base element in the file, which is <?xml ?>
xNode = xDoc.DocumentElement
'Goto the next sibling of current node, which is <quiz>
xNode = xNode.NextSibling
'Goto the first child of current node, which is <mchoice>
xNode = xNode.FirstChild
'Goto the first child of current node, which is <quiz>
xNode = xNode.FirstChild
'Print the content of current node
Response.Write("The question is: " & xNode.InnerHtml)
It is definitely a tedious task, particularly if you want to address nodes located at a very low level in the hierarchy. Luckily, we can utilize the XPath
language to more directly address a specific node or a group of nodes. If you are unfamiliar with XPath, it will be briefly explained in the next section.
The SelectNodes
method of the XMLNode and XMLDocument class' accepts an XPath string and returns a collection of XMLNode objects, called XMLNodeList
. Another method, SelectSingleNode
, does just the same thing but return only a single XMLNode object.
'Using SelectNodes to address all answers of the first multiple choice
Dim xNodeList As XMLNodeList
Dim i as Integer
xNodeList = xDoc.SelectNodes("/quiz/mchoice[1]/answer")
For i = 0 to xNodeList.Count-1
Response.Write("<p>" & xNodeList.Item(i).InnerHtml)
Next
'Using SelectSingleNode to select the first question of the first multiple choice
Dim xNode as XMLNode
xNode = xDoc.SelectSingleNode("/quiz/mchoice[1]/question")
Response.Write("The question is: " & xNode.InnerHtml)
XPath
XPath is a language to address specific nodes in an XML document. It could address a single node or a group of nodes by describing its hierarchy relationship in a string, therefore it is often called an XPath string. If you are familiar with file path or URL, then the concept of XPath is nothing new.
Read the XPath string from left to right and you will be able to figure out the node it is addressing. Except for several conditions and functions, XPath is actually easy to use. The following table demonstrates some usage of XPath against quiz.xml:
XPath String | Result |
/quiz | Select the root node of XML including all elements it contains. |
/quiz/mchoice | Select all mchoice child elements of the quiz |
/quiz/mchoice[1] | Select the first mchoice (multiple choice) child element of the quiz |
/quiz/mchoice[1]/question | Select all questions of the first multiple choice of the quiz |
/quiz/mchoice[1]/answer[4] | Select the fourth answer of the first multiple choice of the quiz |
/quiz/mchoice[1]/answer[4]/@correct | Select 'correct' attribute of the fourth answer of the first multiple choice of the quiz |
XPath contains a lot more surprises. If you are interested enough to explore more, check out the XPath Tutorial at W3CSchools.
Conclusions
This article presented an online quiz as a tool to add interactivity to your web site. It also explored several topics like recursive scripts, navigating and manipulating XML documents using the XML DOM, a glimpse of the XPath language, and a brief discussion about state maintenance.