XPath help please

  • Thread starter Thread starter roidy
  • Start date Start date
R

roidy

Take the following xml file:-

<Data>
<Fruit>
<Name>Apple</Name>
<Color>Green</Color>
<Value>100</Value>
</Fruit>
<Name>Orange</Name>
<Color>Orange</Color>
<Value>75</Value>
</Fruit>
<Fruit>
<Name>Plum</Name>
<Color>Purple</Color>
</Fruit>
</Data>

Now in code I`m looping through 'Fruit' nodes:-

Dim xpathDoc = New XPathDocument("test.xml")
Dim xmlNav = xpathDoc.CreateNavigator()
Dim xmlNI = xmlNav.Select("/Data/Fruit")

While (xmlNI.MoveNext())

How to get the value of Name node?
How to get the value of Color node?
How to get the value of Value node?

End While


I`ve looked at quite a few examples and none explain how to get the value of
a child node of the current node. Help please.

Rob
 
Ok here`s what I`ve come up with:-

While (xmlNI.MoveNext())

If xmlNI.Current.MoveToChild("Name", "") Then
name = xmlNI.Current.Value
xmlNI.Current.MoveToParent()
End If

If xmlNI.Current.MoveToChild("Color", "") Then
color= xmlNI.Current.Value
xmlNI.Current.MoveToParent()
End If

If xmlNI.Current.MoveToChild("Value", "") Then
value= xmlNI.Current.Value
xmlNI.Current.MoveToParent()
End If

End While


This works but is it the best way to do it?

Rob
 
roidy said:
Take the following xml file:-

<Data>
<Fruit>
<Name>Apple</Name>
<Color>Green</Color>
<Value>100</Value>
</Fruit>
<Name>Orange</Name>
<Color>Orange</Color>
<Value>75</Value>
</Fruit>
<Fruit>
<Name>Plum</Name>
<Color>Purple</Color>
</Fruit>
</Data>

Now in code I`m looping through 'Fruit' nodes:-

Dim xpathDoc = New XPathDocument("test.xml")
Dim xmlNav = xpathDoc.CreateNavigator()
Dim xmlNI = xmlNav.Select("/Data/Fruit")

While (xmlNI.MoveNext())

How to get the value of Name node?
How to get the value of Color node?
How to get the value of Value node?

End While


I`ve looked at quite a few examples and none explain how to get the
value of a child node of the current node. Help please.

As long as you know the child element exists it is easy e.g.

For Each fruit As XPathNavigator In
xpathDoc.CreateNavigator().Select("/Data/Fruit")
Dim name = fruit.SelectSingleNode("Name").Value
Dim color = fruit.SelectSingleNode("Color").Value
' use/output name/value here
Next

In the case of the Value element you will then need to check e.g.

For Each fruit As XPathNavigator In
xpathDoc.CreateNavigator().Select("/Data/Fruit")
Dim name As String = fruit.SelectSingleNode("Name").Value
Dim color As String = fruit.SelectSingleNode("Color").Value

Dim valueEl As XPathNavigator = fruit.SelectSingleNode("Value")
If valueEl IsNot Nothing Then
Dim value As String = valueEl.Value
Else
' handle case that no Value child element was found
End If
Next
 
Thanks that`s what I was looking for, I just placed into a function because
not all of the child nodes may exist for each parent node:-

Function ReadChildNode(ByVal navigator As XPathNavigator, _
ByVal nodename As String) As String
Dim result As String = ""
Dim node = navigator.SelectSingleNode(nodename)

If node IsNot Nothing Then
Return node.Value
End If

Return result
End Function


For Each fruit As XPathNavigator In _
xpathDoc.CreateNavigator().Select("/Data/Fruit")
Dim name = ReadChildNode(fruit,"Name")
Dim color = ReadChildNode(fruit,"Color")
Dim value = ReadChildNode(fruit,"Value")
Next

Now the function ReadChildNode takes care of weather the node exists or not.

Thanks again
Rob
 
And of course that should of been simplified to :-

Function ReadChildNode(ByVal navigator As XPathNavigator, _
ByVal nodename As String) As String
Dim node = navigator.SelectSingleNode(nodename)

If node IsNot Nothing Then
Return node.Value
End If

Return Nothing
End Function


roidy said:
Thanks that`s what I was looking for, I just placed into a function
because not all of the child nodes may exist for each parent node:-

Function ReadChildNode(ByVal navigator As XPathNavigator, _
ByVal nodename As String) As String
Dim result As String = ""
Dim node = navigator.SelectSingleNode(nodename)

If node IsNot Nothing Then
Return node.Value
End If

Return result
End Function


For Each fruit As XPathNavigator In _
xpathDoc.CreateNavigator().Select("/Data/Fruit")
Dim name = ReadChildNode(fruit,"Name")
Dim color = ReadChildNode(fruit,"Color")
Dim value = ReadChildNode(fruit,"Value")
Next

Now the function ReadChildNode takes care of weather the node exists or
not.

Thanks again
Rob
 
Thanks that`s what I was looking for, I just placed into a function because
not all of the child nodes may exist for each parent node:-

Function ReadChildNode(ByVal navigator As XPathNavigator, _
ByVal nodename As String) As String
Dim result As String = ""
Dim node = navigator.SelectSingleNode(nodename)

If node IsNot Nothing Then
Return node.Value
End If

Return result
End Function


For Each fruit As XPathNavigator In _
xpathDoc.CreateNavigator().Select("/Data/Fruit")
Dim name = ReadChildNode(fruit,"Name")
Dim color = ReadChildNode(fruit,"Color")
Dim value = ReadChildNode(fruit,"Value")
Next

Now the function ReadChildNode takes care of weather the node exists or not.

Thanks again
Rob



Martin Honnen said:
As long as you know the child element exists it is easy e.g.

For Each fruit As XPathNavigator In
xpathDoc.CreateNavigator().Select("/Data/Fruit")
Dim name = fruit.SelectSingleNode("Name").Value
Dim color = fruit.SelectSingleNode("Color").Value
' use/output name/value here
Next

In the case of the Value element you will then need to check e.g.

For Each fruit As XPathNavigator In
xpathDoc.CreateNavigator().Select("/Data/Fruit")
Dim name As String = fruit.SelectSingleNode("Name").Value
Dim color As String = fruit.SelectSingleNode("Color").Value

Dim valueEl As XPathNavigator = fruit.SelectSingleNode("Value")
If valueEl IsNot Nothing Then
Dim value As String = valueEl.Value
Else
' handle case that no Value child element was found
End If
Next

Have you considered Linq-to-XML?

Option Explicit On
Option Strict On
Option Infer On

Module Module1


Sub Main()

Dim data = <Data>
<Fruit>
<Name>Apple</Name>
<Color>Green</Color>
<Value>100</Value>
</Fruit>
<Fruit>
<Name>Orange</Name>
<Color>Orange</Color>
<Value>75</Value>
</Fruit>
<Fruit>
<Name>Plum</Name>
<Color>Purple</Color>
</Fruit>
</Data>

Dim fruits = From fruit In data.Descendants("Fruit") Select _
New With {.Name = fruit.Element("Name").Value, _
.Color = fruit.Element("Color").Value, _
.Value = If(fruit.Element("Value") IsNot Nothing, _
fruit.Element("Value").Value, "N/A")}

For Each fruit In fruits
Console.WriteLine("Name = {0}, Color = {1}, Value = {2}", _
fruit.Name, fruit.Color, fruit.Value)
Next
End Sub

End Module

Just a thought :)
 
Thanks Tom is that quicker than XPath as the xml files I`m dealing with are
quite large, the fruit data was just a generic example to get my point
across. Also how would you load the xml from a file or from the web instead
of hard coding it into the program?
 
Thanks Tom is that quicker than XPath as the xml files I`m dealing with are
quite large, the fruit data was just a generic example to get my point
across. Also how would you load the xml from a file or from the web instead
of hard coding it into the program?

My experience with linq to xml is that it is quite fast, though I have not
done any formal benchmarking :) So, you might want to compare... Just so you
know , you can actually combine XPath with linq-to-xml, so it's not an either
or situation.

As for loading, I used a vb xml litteral for ease of example :) Look at the
XElement.Load method's overloads. From a local file:

Dim data As XElement = XElement.Load (path)

There are overloads that take XmlReader, TextReader, or String - so, you have
a few options there for reading from the web - something like the following
air-code:

Dim wc As New System.Net.WebClient()
Dim data As XElement = XElement.Load (wc.DownloadString (url))

Anyway, just thought I might give you something else to look at.
 
Back
Top