Question Choosing a structure to manipulate xml data

gusset25

Member
Joined
Apr 29, 2010
Messages
12
Programming Experience
5-10
Hi

Could I have vbdotnet's collective thoughts please?

I am about to write a sub in my gameshow program (multiple choice questions A-D, eight contestants). I currently find myself paralysed by the number of ways of doing a simple task.

The sub will take some well-formed xml contestant response data, identify a particular node (a group of responses), put its child elements (responses) into a structure of some kind, sort the responses according to who gave the response most quickly, filter the responses for a duff choice (E and above) and then perform a calculation (the % who got the question correct).

What is the best combination of elegance and me being able to work out the details?

  • Should I parse the xml data in its natural format with the xPath class? I am new to this and there is a learning curve for me.
  • Ditto with the XmlDocument class
  • (With thanks to Matt, LINQ
  • I am more familiar with databases. Should I create a disconnected recordset? If so, must I loop through each response or is there a more elegant way to populate the recordset?
  • Should I use an array?
  • Or a collection?

The xml's structure, in pseudo-code, is this:

-quiz_session
--questionsgroup
----question
-----responsesgroup
-------response
-------response
-------response
-------(more responses)
----question
-----responsesgroup
-------response
-------response
-------response

Below are some sample data consisting of two questions being answered by eight contestants.

Thanks for any contributions!

<session id="56805FDEA6">
<questionsgroup count="2">
<question id="1">
<topic id="Countries">
</topic>
<text>What is the capital of France</text>
<date>15/05/2010</date>
<time>17:48:56</time>
<answers count="4">
<answer><text>Paris</text>
</answer>
<answer><text>Berlin</text>
</answer>
<answer><text>Cassablanca</text>
</answer>
<answer><text>Cardiff</text>
</answer>
</answers>
<responsesgroup starttime="634095425252343750" endtime="634095425361093750">
<response id="1" time="634095425289687500">2</response>
<response id="2" time="634095425289687501">2</response>
<response id="3" time="634095425289687502">2</response>
<response id="4" time="634095425289687503">2</response>
<response id="5" time="634095425289687504">2</response>
<response id="6" time="634095425289687505">2</response>
<response id="7" time="634095425289687506">9</response>
<response id="8" time="634095425289687507">3</response>
</responsesgroup>
</question>
<question id="2">
<topic id="Sayings">
</topic>
<text>What might you find in a poke?</text>
<date>15/05/2010</date>
<time>18:28:53</time>
<answers count="4">

<answer><text>Pig</text>
</answer>

<answer><text>Calf</text>
</answer>

<answer><text>Horse</text>
</answer>

<answer><text>Donkey</text>
</answer>
</answers>
<responsesgroup starttime="634095425414687500" endtime="634095449334843750">
<response id="1" time="634095425444531250">1</response>
<response id="2" time="634095425444531251">1</response>
<response id="3" time="634095425444687502">1</response>
<response id="4" time="634095425444687503">1</response>
<response id="5" time="634095425444687504">1</response>
<response id="6" time="634095425444687505">1</response>
<response id="7" time="634095425444687506">9</response>
<response id="8" time="634095425444687507">4</response>
</responsesgroup>
</question>
</questionsgroup>
</session>
 
Last edited:
Take a look at the XML section on the boards here. I see you're using .NET 4.0 so I'd suggest using LINQ against your XML file. I'm not seeing where you've got the correct answer in your XML file so that will need to be added to calculate the % correct.

Here's a recent thread where I showed how to use LINQ against an XML file into an anonymous type: http://www.vbdotnetforums.com/xml/40914-parsing-xml-nodes-attributes.html.

I'd also suggest taking a look at the LINQ samples page on msdn: 101 LINQ Samples
 
ok - great, thanks, will do.

well spotted on the absence of the correct answer. the xml file doesn't know anything about that so that calculation will have to take place in vb.net once the numbers are in.
 
Here is what I have so far. I would appreciate some help in finishing this off - i think it's just the two bits in square brackets...

Const XMLDOCFILEPATH As String = "C:\Documents and Settings\All Users\Documents\programming\Nillionaire\AskTheAudience\TPSession.xml"
Dim xDoc As XDocument

xDoc = XDocument.Load(XMLDOCFILEPATH)


Dim xmlQuery As [***some object - my project is strongly-typed***]
xmlQuery = from responsesgroup In xDoc.Descendants.Elements("response") _
Where <responsesgroup> [***last responsesgroup in the xml document***] _
and responsesgroup.<response>.Value() >"A" _
responsesgroup.<response>.value() < "D" _
Select New With { _
.id = response.Attribute("id").Value, _
.responsetime = response.Attribute("time").Value, _
.responsetext = responsesgroup.<response>.Value() _
order by cdbl(response.attribute("time").value)}
For Each result In xmlQuery
Debug.WriteLine(result.id & " " & result.responsetime & " " & result.responsetext)
Next result
 
Last edited:
This example shows how to grab the whole responsesgroup and get information such as starttime, endtime and create a calculated elapsed time for the question.

From there you can see how another LINQ query was used to get an IEnumerable of response filtering out answers that aren't viable and ordered by time. It should also be noted the use of Ancestors to back out into the responsesgroup to get the endtime attribute for calculating the elapsed time.

VB.NET:
        Dim xDoc = XDocument.Load("C:\temp\questions.xml")
        Dim results = (From group In xDoc...<responsesgroup> _
                     Select New With { _
                         .StartTime = group.@starttime, _
                         .EndTime = group.@endtime, _
                         .Elapsed = CDbl(group.@endtime) - CDbl(group.@starttime), _
                         .Responses = (From resp In group.<response> _
                                       Where resp.Value > 0 AndAlso resp.Value < 5 _
                                       Order By resp.@time _
                                       Select New With { _
                                           .Id = resp.@id, _
                                           .Time = resp.@time, _
                                           .ElapsedTime = CDec(.Time) - CDec(resp.Ancestors.@starttime), _
                                           .Answer = resp.Value
                                       })
                     }).LastOrDefault

        MessageBox.Show(String.Format("Last Question Results - Start Time: {0} End Time: {1} Elapsed Time: {2}", _
                                      results.StartTime, _
                                      results.EndTime, _
                                      results.Elapsed))

        For Each result In results.Responses
            MessageBox.Show(String.Format("Result ID: {0} Elapsed Time: {1} Answer: {2}", _
                                          result.Id, _
                                          result.ElapsedTime, _
                                          result.Answer))
        Next
 
Back
Top