Question childnodes with arguments

sandriekus

Member
Joined
Apr 20, 2009
Messages
9
Programming Experience
Beginner
a little bit from my xml:

HTML:
<lesson id="13">
  <periods>1</periods>
  <lesson_subject id="SU" />
  <lesson_teacher id="HA" />
  <lesson_classes id="CL" />
</lesson>
<lesson id="14">
  <periods>2</periods>
  <lesson_subject id="OW" />
  <lesson_teacher id="PO" />
  <lesson_classes id="CF" />
</lesson>

how can i get the information from <periods> with the argument "lesson_teacher id="HA"" (whitch is 1 in this example)?

to get the lesson id i use the following code:

VB.NET:
Dim getlessonid As String = String.Format("//lesson[lesson_teacher/@id='{0}']/@id", "HA")
 
This should get you started. Example of pulling the InnerText from periods and the id attribute value from lesson_subject.

VB.NET:
		Dim doc As New XmlDocument
		doc.Load("C:\Temp\lesson.xml")
		Dim id As String = "13"
		Dim xpath As String = String.Format("//lesson[@id={0}]", id)
		Dim node As XmlNode = doc.SelectSingleNode(xpath)

		Dim periods As Integer = CInt(node.Item("periods").InnerText)
		Dim subject As String = node.Item("lesson_subject").Attributes("id").Value

You'll want to check your day & period tags because the opening and closing aren't the same.
 
how can i get the information from <periods> with the argument "lesson_teacher id="HA""
VB.NET:
//lesson[lesson_teacher/@id='{0}']/periods
The meaning of this expression is get //lesson/periods node(s) where //lesson/lesson_teacher/@id = 'AHA'. Can you see the paths? XPath Tutorial
 
yes i can see it. but it doesn't work ...

my xml:
HTML:
<lesson id="13">
  <periods>1</periods>
  <lesson_subject id="SU" />
  <lesson_teacher id="HA" />
  <lesson_classes id="CL" />
  <times>
    <time>
      <day>4</day>
      <period>5</period>
      <room id="6" />
    </time>
  </times>
</lesson>
<lesson id="14">
  <periods>2</periods>
  <lesson_subject id="OW" />
  <lesson_teacher id="PO" />
  <lesson_classes id="CF" />
  <times>
    <time>
      <day>7</day>
      <period>8</period>
      <room id="9" />
    </time>
  </times>
</lesson>

my code:
VB.NET:
Dim doc As New Xml.XmlDocument
        doc.Load("C:\TEMP\doc.xml")
        Dim getlessonid As String = String.Format("//lesson[lesson_teacher/@id='{0}']/@id", "HA")
        Dim getperiods As String = String.Format("//lesson[lesson_teacher/@id='{0}']/periods", "HA")

        For Each node As XmlNode In doc.SelectNodes(getperiods)
            ListBox1.Items.Add(node.Value)
            ListBox1.Items.Add("----------------------")
        Next

when i run it is telling me that my node.value is 0??
and by the way is there a trick or something to select more strings to add to the listbox, sort like this:

VB.NET:
For Each node As XmlNode In doc.SelectNodes(getlessonid, getperiods)
            ListBox1.Items.Add(node.Value)
            ListBox1.Items.Add("----------------------")
        Next
 
Last edited:
my node.value is 0??
Not 0, null (Nothing in VB). Change node.Value to node.InnerText. If you look in help for XmlNode.Value Property you will see for which node types it is valid to use this property.
is there a trick or something to select more strings
No, you can only select one path. If the path can't include all the nodes you want you have to make an additional selection. Look for teh common denominator and select this, just lookup child nodes from there. In this case you clearly would want to select all the lesson nodes (of a particular lesson_teacher/@id).
VB.NET:
Dim getlessons As String = String.Format("//lesson[lesson_teacher/@id='{0}']", "HA")
For Each node As Xml.XmlNode In doc.SelectNodes(getlessons)
    Dim id As String = node.SelectSingleNode("@id").Value
    Dim periods As String = node.SelectSingleNode("periods").InnerText
    ListBox1.Items.Add(id & " - " & periods)
Next
 
i've got two questions left:

HTML:
<lesson id="13">
  <periods>2</periods>
  <lesson_subject id="SU" />
  <lesson_teacher id="HA" />
  <lesson_classes id="CL" />
  <times>
    <time>
      <day>4</day>
      <period>5</period>
      <room id="6" />
    </time>
    <time>
      <day>4</day>
      <period>6</period>
      <room id="6" />
    </time>
  </times>
</lesson>

question 1:

sometimes (not with all teachers) there are more than 1 "times" (this happens when the teacher is booked for more lessons after eachother.. The number of times is displayed in "periods". so when the teacher has Periods 2, there are 2 "times" how can i display that?

my code only shows the first "time":

VB.NET:
For Each node As Xml.XmlNode In rooster.SelectNodes(getlessons)
    Dim lessonid As String = node.SelectSingleNode("@id").Value
    Dim periods As String = node.SelectSingleNode("periods").InnerText
    Dim lesson_subject As String = node.SelectSingleNode("lesson_subject/@id").Value
    Dim lesson_teacher As String = node.SelectSingleNode("lesson_teacher/@id").Value
    Dim lesson_classes As String = node.SelectSingleNode("lesson_classes/@id").Value
    Dim day As String = node.SelectSingleNode("times/time/day").InnerText
    Dim period As String = node.SelectSingleNode("times/time/period").InnerText
    Dim room As String = node.SelectSingleNode("times/time/room/@id").Value

    ListBox1.Items.Add("lesson id: " & lessonid)
    ListBox1.Items.Add("periods: " & periods)
    ListBox1.Items.Add("lesson_subject id: " & lesson_subject)
    ListBox1.Items.Add("lesson_teacher id: " & lesson_teacher)
    ListBox1.Items.Add("lesson_class id: " & lesson_classes)
    ListBox1.Items.Add("day: " & day)
    ListBox1.Items.Add("period: " & period)
    ListBox1.Items.Add("room id: " & room)
    ListBox1.Items.Add("")
Next

this code works as i told .. but when there are more "times" it shows only the first "time" .. how can display all the "times" (if there are more times)


question 2:

sometimes the "room" is empty .. when i run my program it failed by:
VB.NET:
 Dim room As String = node.SelectSingleNode("times/time/room/@id").Value
because there is no room.
how can u build in a check to look if the child is empty or not?
 
Last edited:
. how can display all the "times" (if there are more times)
Use SelectNodes instead of SelectSingleNode, same xpath. SelectNodes return a XmlNodeList that contain zero or more XmlNode items, so you can loop them:
VB.NET:
for each node as xmlnode in parentnode.selectnodes(xpath)
As a general rule a xpath will always identify none or more nodes that match the path pattern, using SelectSingleNode will return the first match of that path, or a null reference (Nothing) is none is found, SelectNodes will return all matched nodes of the specified path, or an empty node list if none is found.
 
you mean this?

VB.NET:
For Each node As XmlNode In doc.SelectNodes(getlessons)
Dim lessonid As String = node.SelectSingleNode("@id").Value
Dim periods As String = node.SelectSingleNode("periods").InnerText
Dim lesson_subject As String = node.SelectSingleNode("lesson_subject/@id").Value
Dim lesson_teacher As String = node.SelectSingleNode("lesson_teacher/@id").Value
Dim lesson_classes As String = node.SelectSingleNode("lesson_classes/@id").Value
Dim day As String = node.SelectSingleNode("times/time/day").InnerText
Dim period As String = node.SelectSingleNode("times/time/period").InnerText
Dim room As String = node.SelectSingleNode("times/time/room/@id").Value

when i use that ... i dont see the second "time" ..
 
node.SelectSingleNode("times/time/period")
You have multiple, right? As I explained use SelectNodes to select all nodes that match the path.
VB.NET:
for each timeperiod in node.[B]SelectNodes[/B]("times/time/period")
 
the "periods" is the number of times that "times" (and all his childs: day,period and room id) will appear. so if periods is 2.. there are 2 "times" (and all his childs)

if periods is 2 then i will show 2 times the values of the childs of "times"... now it shows only the first values of "times" because i use selectsinglenode?

VB.NET:
For Each node As XmlNode In rooster.SelectNodes(getlessons)
            Dim lessonid As String = node.SelectSingleNode("@id").Value
            Dim periods As String = node.SelectSingleNode("periods").InnerText
            Dim lesson_subject As String = node.SelectSingleNode("lesson_subject/@id").Value
            Dim lesson_teacher As String = node.SelectSingleNode("lesson_teacher/@id").Value
            Dim lesson_classes As String = node.SelectSingleNode("lesson_classes/@id").Value
            Dim day As String = node.SelectSingleNode("times/time/day").InnerText
            Dim room As String = node.SelectSingleNode("times/time/room/@id").Value
            Dim period As String

            For Each timeperiod As XmlNode In node.SelectNodes("times/time/period")
                period = node.SelectSingleNode("times/time/period").InnerText
                ListBox1.Items.Add("period: " & period)
            Next

            ListBox1.Items.Add("lesson id: " & lessonid)
            ListBox1.Items.Add("periods: " & periods)
            ListBox1.Items.Add("lesson_subject id: " & lesson_subject)
            ListBox1.Items.Add("lesson_teacher id: " & lesson_teacher)
            ListBox1.Items.Add("lesson_class id: " & lesson_classes)
            ListBox1.Items.Add("day: " & day)
            ListBox1.Items.Add("room: " & room)
            ListBox1.Items.Add("")
        Next

it's almost done .. if there are 2 "times" there are 2 "period" on the top of the listbox ... but they have both the same value (again the first value) ..
 
Last edited:
Why this??
period = node.SelectSingleNode("times/time/period").InnerText
You have already selected the period nodes, that is what you are For Each looping.
ListBox1.Items.Add("period: " & period)
change to
VB.NET:
ListBox1.Items.Add("period: " & timeperiod.InnerText)
 
how can i select one node from a nodelist?

example:

VB.NET:
For Each something As XmlNode In node.SelectNodes("something")
listbox1.items.add(something.innertext)
next

the output is:

VB.NET:
2
2
2

so there are 3 "somethings" with the value "2".
how can i select the first one?

VB.NET:
node.SelectSingleNode("something").InnerText
shows the error:

System.NullReferenceException
 
If node.SelectNodes("something") returns 3 nodes then node.SelectSingleNode("something") would return the first of those nodes.
 
Back
Top