שתף באמצעות


Check if XML Node Exists in VB2010

Question

Wednesday, July 1, 2015 7:45 AM

Hi - I have got stuck trying to see if an XML node exists in Visual Basic 2010 without causing an error.

Here is the file I am dealing with:

    <?xml version="1.0"?>
    <HamQTH version="2.6" xmlns="http://www.hamqth.com">
    <session>
    <error>Wrong user name or password</error>
    </session>
    </HamQTH>

and I want to see if the 'error' tag-pair exists. I have tried:

hamqthDoc.Load(hamqthStream)
nodes = hamqthDoc.SelectNodes("HamQTH/session")

Dim errorNode As System.Xml.XmlNode = nodes.Item(0).SelectSingleNode("error")
If errorNode IsNot Nothing Then...

If nodes.Item(0).SelectSingleNode("error") IsNot Nothing Then..

If Not IsNothing(nodes.Item(0).SelectSingleNode("error")) Then...

and they all cause:

NullReferenceException was unhandled: Object reference not set to an instance of an object.

After an hour of Googling, I still have not found any code that works.

Short of catching the error in an error-handler, what is the correct way to do this in VB2010, please?

All replies (13)

Wednesday, July 1, 2015 10:15 AM ✅Answered | 1 vote

Here is another way:

        Dim xe As XElement

        xe = XElement.Load("pathname to file or URI here")

        For Each el As XElement In xe.Descendants
            If el.Name.LocalName = "session" Then
                For Each els As XElement In el.Descendants
                    If els.Name.LocalName = "error" Then
                        Stop
                    End If
                Next
            End If
        Next

'Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it.'  JohnWein

Multics

My Serial Port Answer


Wednesday, July 1, 2015 8:54 AM | 1 vote

I would use something like

 Dim hamqthdoc As XDocument
        Dim eElements As List(Of XElement)
     
        hamqthdoc = XDocument.Load("YourXmlFileLocation")

        eElements = (From elements In hamqthdoc.Descendants
                            Where (elements.Name.LocalName.ToString() = "session")
                            Select elements).ToList()

        For Each z As XElement In eElements
            MessageBox.Show(z.Value)
        Next

Wednesday, July 1, 2015 9:48 AM

XmlDocument.GetElementsByTagName Method

This just gets the first element item with the tag name of "error" (index 0). If there were more items with that tag name then I suppose you could use a loop to get all of them altering the code a bit I believe.

Option Strict On

Imports System.Xml

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.Location = New Point(CInt((Screen.PrimaryScreen.WorkingArea.Width / 2) - (Me.Width / 2)), CInt((Screen.PrimaryScreen.WorkingArea.Height / 2) - (Me.Height / 2)))
        Label1.Text = "Waiting"
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim doc As New XmlDocument()
        doc.LoadXml(My.Computer.FileSystem.ReadAllText("C:\Users\John\Desktop\HamQTH.Xml"))
        Dim root As XmlElement = doc.DocumentElement
        Label1.Text = root.GetElementsByTagName("error").Item(0).InnerText
    End Sub

End Class

La vida loca


Wednesday, July 1, 2015 10:03 AM

Hi Rbie - Thanks for your answer, but that just gives an error 'Root Element is Missing'.

Surely there is just a way to simply tell if an XML tag is there or not? I can simulate this working by manually entering the strings sent from a browser, so I know the server is outputting the code and my example has a chance of working. Here is the full code of this example:

Dim hamqthUrl = "http://www.hamqth.com/xml.php?"
Dim hamqthRequest As System.Net.WebRequest
Dim hamqthResponse As System.Net.WebResponse
Dim hamqthStream As System.IO.Stream
Dim hamqthDoc As New System.Xml.XmlDocument
Dim nodes As System.Xml.XmlNodeList
hamqthRequest = System.Net.WebRequest.Create(hamqthUrl & "u=" & hamqthUser & "&p=" & hamqthPass)
hamqthResponse = hamqthRequest.GetResponse()
hamqthStream = hamqthResponse.GetResponseStream()
hamqthDoc.Load(hamqthStream)
nodes = hamqthDoc.SelectNodes("HamQTH/session")

So, within the <session> tag-pair, there will be returned EITHER <session_id>value</session_id> OR <error>value</error>. What I need to do is to see which is returned, and then get the value of the one that is returned.


Wednesday, July 1, 2015 10:39 AM

I suppose this works but I don't particularly care for it since there's probably a method to determine if either "error" or "session_id" exists without using Try/Catch to avoid errors.

Option Strict On

Imports System.Xml
Imports System.Net

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.Location = New Point(CInt((Screen.PrimaryScreen.WorkingArea.Width / 2) - (Me.Width / 2)), CInt((Screen.PrimaryScreen.WorkingArea.Height / 2) - (Me.Height / 2)))
        Label1.Text = "Waiting"
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim request As WebRequest = WebRequest.Create("http://www.hamqth.com/xml.php?")
        request.Credentials = CredentialCache.DefaultCredentials
        Using response As HttpWebResponse = CType(request.GetResponse(), HttpWebResponse)
            Console.WriteLine(response.StatusDescription)
            Using dataStream As IO.Stream = response.GetResponseStream()
                Using reader As New IO.StreamReader(dataStream)
                    Dim responseFromServer As String = reader.ReadToEnd()
                    Dim doc As New XmlDocument()
                    doc.LoadXml(responseFromServer)
                    Dim root As XmlElement = doc.DocumentElement
                    Try
                        Label1.Text = root.GetElementsByTagName("error").Item(0).InnerText
                    Catch ex As Exception
                    End Try
                    Try
                        Label1.Text = root.GetElementsByTagName("session_id").Item(0).InnerText
                    Catch ex As Exception
                    End Try
                End Using
            End Using
        End Using
    End Sub

End Class

Xml displayed on WebSite in I.E.

La vida loca


Wednesday, July 1, 2015 11:07 AM

Weird, I can read the file you posted without any problem, So my guess is you didn't use my exact code or the actual xml file is different from what you posted. This is the result I get


Wednesday, July 1, 2015 11:35 AM

Since the problem is caused by the namespace, try this variant too:

Dim m = New XmlNamespaceManager(hamqthDoc.NameTable)
m.AddNamespace("ns", "http://www.hamqth.com")

Dim error_node = hamqthDoc.SelectSingleNode("/*/ns:session/ns:error", m)

If error_node IsNot Nothing Then
    ' the <error> node exists
    Dim text = error_node.InnerText.Trim
    ...
End If

Wednesday, July 1, 2015 11:36 AM

Hi Multics - thanks, I got my code working using your example. In my xml, there will either be a <session_id>value</session_id> or a <error>value</error> tag contained within the <session> tag-pair, so I was able to do some logic that looked for the value of first one, and then the other.

However for future knowledge, it would still be nice to know how to check if a tag isn't there, without causing an error. Using your loop, I could, of course, wait until the end of the loop and see if a particular tag-name had been encountered. If no one else comes up with something better, that will have to do.


Wednesday, July 1, 2015 11:40 AM

Yes sir, 'Try' would be another way to do it, but I really didn't want to go down that route, as I am already using Try in a larger loop that this code is a part of. Thanks, anyway for taking the time to add your suggestion.


Wednesday, July 1, 2015 2:39 PM | 1 vote

Tim,

You have lots of answers here - I'll add in my suggestion also for what it's worth:

Option Strict On
Option Explicit On
Option Infer Off

Imports System.IO.Path
Imports <xmlns:ns="http://www.hamqth.com">

Public Class Form1
    Private Sub Form1_Load(ByVal sender As System.Object, _
                           ByVal e As System.EventArgs) _
                           Handles MyBase.Load

        Dim desktop As String = _
            My.Computer.FileSystem.SpecialDirectories.Desktop

        Dim xPath As String = Combine(desktop, "Example.xml")

        Dim result As Boolean = CheckIfTagExist(xPath)

        Stop

    End Sub



    Private Function CheckIfTagExist(ByVal filePath As String) As Boolean

        Dim retVal As Boolean = False

        If My.Computer.FileSystem.FileExists(filePath) Then
            Dim xDoc As XElement = XElement.Load(filePath)
            Dim errorTag As XElement = xDoc...<ns:error>.FirstOrDefault

            If errorTag IsNot Nothing Then
                retVal = True
            End If
        End If

        Return retVal

    End Function
End Class

Still lost in code, just at a little higher level.

:-)


Thursday, July 2, 2015 11:18 AM

You are correct - my silly mistake - I had an extra line of code in the processing which stopped your code from working.


Thursday, July 2, 2015 11:40 AM

For some reason yesterday I couldn't see that there was a namespace.  Here is an example based on what Frank posted.  Franks example will work, assuming that he has used the correct namespace, but it can fail if <error> occurs outside of <session>.

        'simulated file
        Dim xe As XElement = <HamQTH version="2.6">
                                 <error>nit is seesion Wrong user name or password</error>
                                 <session>
                                     <error>Wrong user name or password</error>
                                 </session>
                             </HamQTH>

        'xe = XElement.Load("path or uri") 'read file or uri

        'references to elements will need namespaces of the actual XML added
        Dim errorTag As XElement = xe...<error>.FirstOrDefault

        Stop 'examine errorTag

        errorTag = xe...<session>...<error>.FirstOrDefault

        If errorTag IsNot Nothing Then
            Stop
        End If

'Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it.'  JohnWein

Multics

My Serial Port Answer


Thursday, July 2, 2015 1:26 PM

... but it can fail if <error> occurs outside of <session>.

Well yes, I did make the assumption that what he showed is from what he wanted to use it for. ;-)

Still lost in code, just at a little higher level.

:-)