12

I have an XML file from a URL API (the URL I have not shared since it allows access to secure info). From this file I want to get certain info out. My problem is, once I am in the parent node (eventNode) I want to simply be able to get the data from specific child nodes.

For example if eventNode was <event><ID>1</ID>...<title>event 1</title></event>, how would I get 1 from just knowing the node name is ID (or any other value I want to pull out)?

I have looked a lot through forums and the .SelectSingleNode has given me no luck. Also .selectNodes will not act like a normal list of nodes in an XML string. I don't know if this is due to the method I'm using to parse my XML file.

Sub ListEvents()

Dim strPath As String

strPath = getAPI("GetEvents", "filter=&orderBy=")

Dim xmlDocument As MSXML2.DOMDocument60
Set xmlDocument = New DOMDocument60

With CreateObject("MSXML2.XMLHTTP")
    .Open "GET", strPath, False
    .send
    xmlDocument.LoadXML .responseText
End With

Dim lvl1 As IXMLDOMNode: Dim lvl2 As IXMLDOMNode
Dim eventNode As IXMLDOMNode: Dim isNode As IXMLDOMNode

For Each lvl1 In xmlDocument.ChildNodes
    For Each lvl2 In lvl1.ChildNodes
        For Each eventNode In lvl2.ChildNodes
            If eventNode.HasChildNodes Then
                'Here is where I want code to find specific child node
                'without having to look at every node.
            End If
        Next
    Next
Next

End Sub

Sample XML:

<?xml version="1.0" encoding="utf-8" ?> 
<ResultsOfListOfEvent xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.regonline.com/api">
  <Success>true</Success> 
  <Data>
    <APIEvent>
      <ID>111</ID> 
      <CustomerID>222</CustomerID> 
      <ParentID>0</ParentID> 
      <Status>Testing</Status> 
      <Title>Event Name</Title> 
      <ClientEventID /> 
      <TypeID>9</TypeID> 
      <TimeZone>GMT</TimeZone> 
      <CurrencyCode>GBP</CurrencyCode> 
      <AddDate>2013-12-18T02:34:09.357</AddDate> 
      <Channel>Running</Channel> 
      <IsWaitlisted>false</IsWaitlisted> 
    </APIEvent>
    <APIEvent>
      <ID>112</ID> 
      <CustomerID>223</CustomerID> 
      <ParentID>0</ParentID> 
      <Status>Testing</Status> 
      <Title>Event Name</Title> 
      <ClientEventID /> 
      <TypeID>9</TypeID> 
      <TimeZone>GMT</TimeZone> 
      <CurrencyCode>GBP</CurrencyCode> 
      <AddDate>2013-12-18T02:34:09.357</AddDate> 
      <Channel>Running</Channel> 
      <IsWaitlisted>false</IsWaitlisted> 
    </APIEvent>
  </Data>
</ResultsOfListOfEvent>

I want to output the text in each <ID> (i.e. 111 and 112) and each <Title>. This is only an example, depending on the API I run I will want to be able to pick and choose what information I pull.

Andriy M
  • 76,112
  • 17
  • 94
  • 154
yoz1234
  • 129
  • 1
  • 1
  • 8
  • Post sample xml and expected output – Pankaj Jaju Jan 10 '14 at 14:41
  • Please also post sample output that you are expecting ... as in which child nodes you want to fetch – Pankaj Jaju Jan 10 '14 at 15:02
  • I want to output the text in each (i.e. 111 and 112) and each . This is only an example, depending on the API I run I will want to be able to pick and choose what information I pull. – yoz1234 Jan 10 '14 at 15:08
  • [**Dynamically search for data In an XML file with VBA**](http://stackoverflow.com/questions/19729601/dynamically-search-for-data-in-an-xml-file-with-vba/19730346#19730346) – Santosh Jan 10 '14 at 15:08
  • Santosh, does this go through every child node? I need to be able to say given x child nodes return the text from and without having to look at every single node. I.e. some kind of getNodeText("ID") – yoz1234 Jan 10 '14 at 15:20

2 Answers2

12

Try this - you can modify the below code to fetch any child node

Set xmlDoc = CreateObject("Microsoft.XMLDOM")
xmlDoc.SetProperty "SelectionLanguage", "XPath"
xmlDoc.Async = False
xmlDoc.Load("C:\Users\pankaj.jaju\Desktop\Test.xml")

Set nodeXML = xmlDoc.getElementsByTagName("ID")
For i = 0 To nodeXML.Length - 1
    MsgBox nodeXML(i).Text
Next

Edit from question author:

This worked great. For any readers this is how I used the answer above to adapt my code (since I load the XML from a URL - not a file):

Sub ListEvents()
Dim myURL As String

myURL = getAPI("GetEvents", "filter=&orderBy=")

Set xmlDoc = CreateObject("Microsoft.XMLDOM")
xmlDoc.setProperty "SelectionLanguage", "XPath"
xmlDoc.async = False

With CreateObject("MSXML2.XMLHTTP")
    .Open "GET", myURL, False
    .send
    xmlDoc.LoadXML .responseText
End With

Set nodeXML = xmlDoc.getElementsByTagName("ID")
For i = 0 To nodeXML.Length - 1
    MsgBox nodeXML(i).Text
Next
End Sub
Community
  • 1
  • 1
Pankaj Jaju
  • 5,371
  • 2
  • 25
  • 41
11

Here's a slightly different approach that builds on Pankaj Jaju's answer above.

Notes:

  • uses the MSXML2 namespace as the old Microsoft.XMLDOM one is only maintained for legacy support - see here
  • uses the "SelectionNamespaces" property to fix the problem which MSXML2 has with XPath when a document has a default namespace - see here. We create a namespace called r (any name would do though) that has the same URI reference as the default namesepace in the document (http://www.regonline.com/api in this case)
  • uses that new namespace in XPath as the prefix for any element which has an unprefixed name. That's a complicated way of saying that rather than looking for /ID, we'll look for /r:ID

Here is the code:

Sub foo()

Dim xmlDoc As Object
Dim xmlNodeList As Object
Dim xmlNode As Object

Set xmlDoc = CreateObject("MSXML2.DOMDocument.6.0")
xmlDoc.setProperty "SelectionNamespaces", "xmlns:r='http://www.regonline.com/api'"
xmlDoc.async = False
xmlDoc.Load "C:\Users\colin\Desktop\yoz1234.xml"

Set xmlNodeList = xmlDoc.selectNodes("/r:ResultsOfListOfEvent/r:Data/r:APIEvent/r:ID")

For Each xmlNode In xmlNodeList
    MsgBox xmlNode.Text
Next xmlNode

End Sub
barrowc
  • 10,444
  • 1
  • 40
  • 53