title: Parsing XML in Visual Basic
body: <p>I am having difficulty figuring out how to "properly" parse an XML response in Visual Basic.  I happen to be running Visual Studio 2013.  The response I get from the API I am querying looks exactly like this (some data changed to protect the innocent):</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8" standalone="yes"?&gt;
  &lt;person id="123456"&gt;
      &lt;hos-status as-of="2015-05-20T18:53:39.592Z"&gt;
          &lt;duty-status&gt;ON&lt;/duty-status&gt;
          &lt;availability&gt;
              &lt;drive&gt;22020000&lt;/drive&gt;
              &lt;shift&gt;22020000&lt;/shift&gt;
              &lt;cycle&gt;151320000&lt;/cycle&gt;
          &lt;/availability&gt;
          &lt;rest-break&gt;
              &lt;max-drive&gt;420000&lt;/max-drive&gt;
              &lt;rest-remaining&gt;1800000&lt;/rest-remaining&gt;
          &lt;/rest-break&gt;
          &lt;daily-log-summary date="2015-05-20"&gt;
              &lt;duty-status code="OF"&gt;25200000&lt;/duty-status&gt;
              &lt;duty-status code="SL"&gt;0&lt;/duty-status&gt;
              &lt;duty-status code="DR"&gt;7800000&lt;/duty-status&gt;
              &lt;duty-status code="ON"&gt;20580000&lt;/duty-status&gt;
          &lt;/daily-log-summary&gt;
          &lt;daily-log-summary date="2015-05-19"&gt;
              &lt;duty-status code="OF"&gt;51600000&lt;/duty-status&gt;
              &lt;duty-status code="SL"&gt;0&lt;/duty-status&gt;
              &lt;duty-status code="DR"&gt;8580000&lt;/duty-status&gt;
              &lt;duty-status code="ON"&gt;26220000&lt;/duty-status&gt;
          &lt;/daily-log-summary&gt;
      &lt;/hos-status&gt;
      &lt;location as-of="2015-05-20T18:52:40.000Z"&gt;
          &lt;position lat="12.345678" lon="-12.345678" accuracy="3"/&gt;
          &lt;speed&gt;12&lt;/speed&gt;
          &lt;bearing&gt;123.45&lt;/bearing&gt;
      &lt;/location&gt;
  &lt;/person&gt;
  </code></pre>
  
  <p>I can parse it but the way I am doing it is certainly not intuitive.  I have spent several days reading up on it and all I can find are ways that look about as ugly as what I am doing.  Obviously I am missing something fundamental and I'd like suggestions on what to read so I can learn the proper way.</p>
  
  <p>Here is the code / process I am using.  First I call the API to get a response via the following function:</p>
  
  <pre><code>Public Function getCurlXML(theURL As String) As Xml.XmlDocument
      getCurlXML = New Xml.XmlDocument
      Dim wHeader As WebHeaderCollection = New WebHeaderCollection()
      wHeader.Clear()
      Dim wRequest As HttpWebRequest = DirectCast(System.Net.HttpWebRequest.Create(theURL), HttpWebRequest)
      wRequest.ContentType = "text/xml"
      wRequest.Headers = wHeader
      wRequest.Method = "GET"
      Dim wResponse As HttpWebResponse = DirectCast(wRequest.GetResponse(), HttpWebResponse)
      Dim sResponse As String = ""
      Using srRead As New StreamReader(wResponse.GetResponseStream())
          sResponse = srRead.ReadToEnd()
      End Using
      getCurlXML.LoadXml(sResponse)
  End Function
  </code></pre>
  
  <p>Below is the code I use to call the above function and the do the parsing:</p>
  
  <pre><code>Public Function getThePersonStatus(personID As String) As Collection
      Dim statusColl As New Collection
      Dim sUrl As String = "https://api.THE.com/api/stuffage/" &amp; personID &amp; "/status?apiKey=" &amp; My.Settings.TheAPIKey
      Dim doc As Xml.XmlDocument = getCurlXML(sUrl)
      Dim statusElemList As XmlNodeList = doc.GetElementsByTagName("hos-status")
      For Each thisNode As XmlNode In statusElemList
        If (thisNode.Name = "hos-status") Then
            statusColl.Add(thisNode.Attributes("as-of").Value.ToString, "hos-as-of")
            statusColl.Add(thisNode("duty-status").InnerText.ToString, "duty-status")
            Dim availElem As XmlNode = thisNode("availability")
            statusColl.Add(availElem("drive").InnerText.ToString, "drive")
            statusColl.Add(availElem("shift").InnerText.ToString, "shift")
            statusColl.Add(availElem("cycle").InnerText.ToString, "cycle")
        End If
      Next
      Dim locationElemList As XmlNodeList = doc.GetElementsByTagName("location")
      For Each thisNode As XmlNode In locationElemList
        statusColl.Add(thisNode.Attributes("as-of").Value.ToString, "loc-as-of")
        statusColl.Add(thisNode("speed").InnerText.ToString, "speed")
        statusColl.Add(thisNode("bearing").InnerText.ToString, "bearing")
        statusColl.Add(thisNode("position").Attributes("lat").Value.ToString, "lat")
        statusColl.Add(thisNode("position").Attributes("lon").Value.ToString, "lon")
        statusColl.Add(thisNode("position").Attributes("accuracy").Value.ToString, "gps-accuracy")
      Next
      getThePersonStatus = statusColl
  End Function
  </code></pre>
  
  <p>Basically I create an XML document from the response then I search for an element that I am interested in and then loop through that element looking for sub nodes that I am interested in.</p>
  
  <p>Is there not a way to load the document and the refer to a specific element in a form similar to:</p>
  
  <pre><code>doc.Elem("person").Elem("hos-status").Elem("availability").Elem("Shift").InnerText
  </code></pre>
  
  <p>I know what elements are there (or should be there) but cannot seem to reference them directly no matter what I try.</p>