I am using a HTTPSecureSocket to send a request to a server that contains information about phones. The request is formed correctly and I receive the following information
This code is in a method that is called when that data appears as a response to the request
vEvent is a variable that holds Event Request made to the Cisco UCM server
vInfo is a Variant that holds the response from the Cisco UCM server
This is a short version of a method that looks at the request and response.
//IF WEâRE DEALING WITH A PHONE COMMAND
If (vObservable isa stdHTTPSS) AND (stdHTTPSS(vObservable).ObservableCallbackCommand = âget_phone_idâ) Then
Select Case vEvent
Case âInvalidItemâ
System.DebugLog(â\n*********************************************************\nâ)
System.DebugLog(vInfo.StringValue)
Printable_Phone_Info_LB.AddRow(stdHTTPSS(vObservable).ObservableCallbackTag,âNot Foundâ)
Case âValidItemâ
Var xml as new XmlDocument
Var nodeList as XmlNodeList
Var root As XmlNode
Var node As XmlNode
// Load XML
Try
xml.LoadXml(vInfo.StringValue)
Catch e As XmlException
MessageBox("XML error: " + e.Message)
Return
End Try
root = xml.DocumentElement
// Get all the Phone Info nodes
nodeList = xml.Xql("//phone") // Find all Phone Info
If root.ChildCount > 0 Then
// Add Phone Info to ListBox
For i As Integer = 0 To nodeList.Length - 1
node = nodeList.Item(i)
Printable_Phone_Info_LB.AddRow(node.GetAttribute("name"), _
node.GetAttribute("model"), _
node.GetAttribute("description"), _
node.GetAttribute("devicePoolName"), _
node.GetAttribute("phoneTemplateName"), _
node.GetAttribute("label"))
Next
'This prints 2 columns of info as a test Printable_Phone_Info_LB.AddRow(stdHTTPSS(vObservable).ObservableCallbackTag,"Found")
End
End Select
End If
Where I attempt to parse this data // Add Phone Info to ListBox and place it on a ListBox nothing is displayed. I have attempted several modifications to grab the information returned associated with the attributes identified above.
How do I properly iterate through to get the information I am attempting to place in the ListBox âPrintable_Phone_Info_LBâ
Youâre not getting the desired results because the items you are looking for are not attributes of the phone nodes, but rather children. Youâll need to iterate the children of the phone node and get their value instead.
For example (simple to show the first one, no Nil checking and not tested). Youâll want to build out the Select with each of the children you need, store them in temporary variables like this, then add it to your listbox.
node = nodeList.Item(i)
Dim phoneName As String
Dim xChild as XmlNode = node.FirstChild
While xChild <> Nil
Select Case xChild.name
Case "name"
phoneName = xChild.Value
End Select
xChild = xChild.NextSibling
Wend
Attributes are within the nodeâs angle brackets. So, at the example you pointed to, ctiid and uuid are attributes.
I appreciate your response and you got me thinking. I found a solution but I am not certain this is the best approach. I came into this thinking like I could walk through this in a similar manner as I do for DBs with many tables. I could not see how to do that and perhaps it is my learning curve on how to do that with XML data.
I have data returned from a request. This link is a file of that returned data. Phone Data Returned
I could be wrong but to me this seems to be a complex data structure. The first data I need is easy to get as it is exactly as you suggested. However there is data in lines, speeddials, and busylampfields that may or may not have data buried inside. Each of the mnemonics mentioned have no entries if nothing exists or indicate the members underneath. In code I walk through this returned data like this
If (vObservable isa stdHTTPSS) AND (stdHTTPSS(vObservable).ObservableCallbackCommand = "get_phone_id") then
Select Case vEvent
Case "InvalidItem"
//System.DebugLog("\n*********************************************************\n")
System.DebugLog(Str(stdHTTPSS(vObservable).LastErrorCode))
System.DebugLog(vInfo)
Printable_Phone_Info_LB.AddRow(stdHTTPSS(vObservable).ObservableCallbackTag,"Not Found")
Error_TF.AddText(Str(vInfo))
Case "ValidItem"
Var xml as new XmlDocument
Var Line_xml as new XmlDocument
Var nodeList, Line_nodeList as XmlNodeList
Var root, Line_root As XmlNode
Var node, Line_node As XmlNode
// Print response from Cisco UCM to debug
System.DebugLog(vInfo.StringValue)
// Load XML
Try
xml.LoadXml(vInfo.StringValue)
Catch e As XmlException
MessageBox("XML error: " + e.Message)
Return
End Try
root = xml.DocumentElement
nodeList = xml.Xql("//phone") // Get all the Phone Info
If root.ChildCount > 0 Then
Printable_Phone_Info_LB.AddRow
For i As Integer = 0 To nodeList.Length - 1
node = nodeList.Item(i)
Var phoneName As String
Var xChild as XmlNode = node.FirstChild
While xChild <> Nil
Select Case xChild.name
Case "name"
phoneName = xChild.LastChild.Value
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, 0) = phoneName
Case "model"
phoneName = xChild.LastChild.Value
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, 1) = phoneName
Case "description"
phoneName = xChild.LastChild.Value
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, 2) = phoneName
Case "devicePoolName"
phoneName = xChild.LastChild.Value
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, 3) = phoneName
Case "phoneTemplateName"
phoneName = xChild.LastChild.Value
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, 4) = phoneName
Case "lines"
// Parse through XML to find "line" which must have at least 1 member
Try
Line_xml.LoadXml(xChild.ToString)
Line_root = Line_xml.DocumentElement
Line_nodeList = Line_xml.Xql("//line") // Get all Phone Info
Var Line_Members As Integer = Line_xml.Xql("//line").Length // How many members?
For xx As Integer = 0 to Line_Members - 1
Line_node = Line_nodeList.Item(xx)
Var Next_Child As XmlNode = Line_node.FirstChild
Var my_nextSib As XmlNode = Next_Child.NextSibling
Var my_nextSib1 As XmlNode = my_nextSib.NextSibling
Var my_nextSib2 As XmlNode = my_nextSib1.NextSibling
Var Next_Child1 As XmlNode = my_nextSib2.FirstChild
Var Next_Child2 As XmlNode = Next_Child1.FirstChild
If xx = 0 Then
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, LNE_column) = Next_Child2.Value
Else
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, LNE_column) = _
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, LNE_column) + ", " + _
Next_Child2.Value
End
Next
Catch e As XmlException
MessageBox("XML error: " + e.Message)
Return
End Try
Case "busyLampFields"
// Check Attribute count becuase there could be 0 - No Speed Dial info
If xChild.AttributeCount > 0 Then
Line_xml.LoadXml(xChild.ToString)
Line_root = Line_xml.DocumentElement
Line_nodeList = Line_xml.Xql("//busyLampField") // Get all Speedial Info
Var busyLampField As Integer = Line_xml.Xql("//busyLampField").Length // How many members?
// Parse through XML to find "speeddials dirn" which could be empty but exists
For xx As Integer = 0 to busyLampField - 1
Line_node = Line_nodeList.Item(xx)
Var Next_Child As XmlNode = Line_node.FirstChild
Var Next_Child1 As XmlNode = Next_Child.FirstChild
If xx = 0 Then
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, BLF_column) = _
Next_Child1.Value
Else
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, BLF_column) = _
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, BLF_column) + ", " + _
Next_Child1.Value
End
Next
End
Case "speeddials"
// Check Attribute count becuase there could be 0 - No Speed Dial info
If xChild.AttributeCount > 0 Then
Line_xml.LoadXml(xChild.ToString)
Line_root = Line_xml.DocumentElement
Line_nodeList = Line_xml.Xql("//speeddial") // Get all Speedial Info
Var SpeedDial_Members As Integer = Line_xml.Xql("//speeddial").Length // How many members?
// Parse through XML to find "speeddials dirn" which could be empty but exists
For xx As Integer = 0 to SpeedDial_Members - 1
Line_node = Line_nodeList.Item(xx)
Var Next_Child As XmlNode = Line_node.FirstChild
Var Next_Child1 As XmlNode = Next_Child.FirstChild
If xx = 0 Then
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, SPD_column) = _
Next_Child1.Value
Else
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, SPD_column) = _
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, SPD_column) + ", " + _
Next_Child1.Value
End
Next
End
End Select
xChild = xChild.NextSibling
Wend
Next
// Set the column widths
SetColumnWidths(Printable_Phone_Info_LB)
End
End Select
End If
For me in particular the sections âlinesâ, âbusyLampFieldsâ, âspeeddialsâ are what I am wondering could be improved on. Basically I learned how to do this with the help of the debugger figuring out how to walk into the data and get the information I needed.
If this is how it is then thatâs fine. Just looking to better understand and see if I can improve on how I can get needed data.
You do not need to keep âloadingâ line_xml. Instead you can just create the desired nodeList with a new .xql query⊠so instead of using â//someNodeNameâ you can use âchild::â and other Xpath Axes to find children of a given node. See: XPath Axes
@Jim_Meyer - thanks. Here is what I came up with next
For Lines: Instead of this
For xx As Integer = 0 to Line_Members - 1
Line_node = Line_nodeList.Item(xx)
Var Next_Child As XmlNode = Line_node.FirstChild
Var my_nextSib As XmlNode = Next_Child.NextSibling
Var my_nextSib1 As XmlNode = my_nextSib.NextSibling
Var my_nextSib2 As XmlNode = my_nextSib1.NextSibling
Var Next_Child1 As XmlNode = my_nextSib2.FirstChild
Var Next_Child2 As XmlNode = Next_Child1.FirstChild
If xx = 0 Then
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, LNE_column) = Next_Child2.Value
Else
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, LNE_column) = _
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, LNE_column) + ", " + _
Next_Child2.Value
End
Next
I came up with this
For xx As Integer = 0 to Line_Members - 1
Var Line_Member1 As XmlNodeList = Line_xml.Xql("//line//dirn//pattern")
Var Line_Member_Node As XmlNode = Line_Member1.Item(0).FirstChild
If xx = 0 Then
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, LNE_column) = Line_Member_Node.Value
Else
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, LNE_column) = _
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, LNE_column) + ", " + _
Line_Member_Node.Value
End
Next
That enables me to grab the specific value and allows me to grab multiple entries if they exist via the loop.
Case "lines"
// Parse through XML to find "line" which must have at least 1 member
Try
Line_xml.LoadXml(xChild.ToString)
For xx As Integer = 0 to Line_xml.Xql("//line").Length - 1 // Get all Phone 'Line' Info using Line_xml.Xql("//line")
Var Line_Member_Node As XmlNode = Line_xml.Xql("//line//dirn//pattern").Item(xx).FirstChild 'Line_Member1.Item(0).FirstChild
If xx = 0 Then
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, LNE_column) = Line_Member_Node.Value
Else
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, LNE_column) = _
Printable_Phone_Info_LB.CellValueAt(Printable_Phone_Info_LB.LastRowIndex, LNE_column) + ", " + _
Line_Member_Node.Value
End
Next
Catch e As XmlException
MessageBox("XML error: " + e.Message)
Return
End Try
dim i as integer
dim x as new XmlDocument
dim xnl as XmlNodeList
dim s as string
x.LoadXml(SpecialFolder.Desktop.Child(âx.xmlâ)) // since I put a copy of your file on my desktop
// âtryâ just in case something goes wrong on the xql line⊠but should only happen if you have a syntax error in the parameter/xpath⊠if it does not find anything it just comes up with an empty nodeList.
try
xnl = x.Xql("//lines/line/dirn/pattern")
for i = 0 to xnl.Length - 1
try // âtryâ here in case the node does not have a FirstChild.Value
s = xnl.Item(i).FirstChild.Value
catch
s = âerrorâ
end try
next
catch
MsgBox(âBad xqlâ)
end try
Your âFor xx As Integer = 0 to Line_xml.Xql(â//line").Length - 1" is forcing the xql to run for each â//lineâ⊠execute the xql once and then step through the nodelist.
I have used one xql to get directly down to each âpatternâ⊠but I could have use multiple nested âxqlâ and âforâ loops to work my way down to that level⊠which works well if you need values in any of the parent nodes⊠like or the âuuidâ attribute in the node⊠but you can still get to those by using âparentâ.
@Jim_Meyer - Thanks for your suggestions. The updated code piece works a bit faster which means when I request many phone devices this could add up to hours in time saved