I have started creating an excel for stock watch in 2010 and havent been able to parse properly.
Instead of getting the columns with [symbol] and prices i only get first four tags and nothing inside data.
This is the code:
Sub getJSON()
Set MyRequest = CreateObject("WinHttp.WinHttpRequest.5.1")
MyRequest.Open "GET", "https://www.nseindia.com/live_market/dynaContent/live_watch/stock_watch/foSecStockWatch.json"
MyRequest.Send
MsgBox MyRequest.ResponseText
Dim jsonText As String
Dim jsonObj As Dictionary
Dim jsonRows As Collection
Dim jsonRow As Collection
Dim ws As Worksheet
Dim currentRow As Long
Dim startColumn As Long
Dim i As Long
Set ws = Worksheets("Sheet1")
ws.Range("A1") = MyRequest.ResponseText
MsgBox ws.Range("A1").Value
jsonText = ws.Range("A1").Value
'jsonText = MyRequest.ResponseText
'Parse it
Set jsonObj = JSON.parse(jsonText)
'Get the rows collection
'Error here'
Set jsonRows = jsonObj("symbol")
'Set the starting row where to put the values
currentRow = 1
'First column where to put the values
startColumn = 2 'B
'Loop through all the values received
For Each jsonRow In jsonRows
'Now loop through all the items in this row
For i = 1 To jsonRow.Count
ws.Cells(currentRow, startColumn + i - 1).Value = jsonRow(i)
Next i
'Increment the row to the next one
currentRow = currentRow + 1
Next jsonRow
End Sub
Also as this is excel 2010 and doing it as a newbie let me know if this is the correct way to parse json as i am going to create multiple excels with different urls.
You need to inspect the JSON structure and write your code accordingly. The [] means collection which you can For Each over the items of. The {} means dictionary which you can loop over the keys of. The blue and green squares (in the image of your JSON below) are string literals (key,value pairs).
You initially get back a dictionary containing a mixture of key, value pairs (e.g. noChg, 5); with one key, data, being to a collection of inner dictionaries.
jsonObj("symbol") if you had parsed with ParseJson and following syntax:
Set jsonObj = JsonConverter.ParseJson(.responseText) '<== dictionary
would have failed as symbol is a key in the inner dictionaries, within the collection data, and not directly accessible from the initial top level JSON dictionary.
Instead, you need to loop the initial dictionary and write out the key, value pairs and test if the key is data. If the key is data, you instead need to loop the items in the collection (each being a dictionary), and loop the keys of those dictionaries.
A little thought as to how you increment row and column counters, and testing for the first time the inner dictionary keys are looped, to get the headers only once, will result in a tidy write out of data to sheet.
NOTE: I am using JSONConverter.bas to parse the JSON. After adding this to the project, I also go to VBE > Tools > References and add a reference to Microsoft Scripting Runtime.
VBA:
Option Explicit
Public Sub GetInfo()
Dim json As Object, item As Object, key As Variant, key2 As Variant, ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
With CreateObject("MSXML2.XMLHTTP")
.Open "GET", "https://www.nseindia.com/live_market/dynaContent/live_watch/stock_watch/foSecStockWatch.json", False
.setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"
.send
Set json = JsonConverter.ParseJson(.responseText) '<== dictionary
End With
Dim r As Long, c As Long, headerRow As Long
For Each key In json '<== Loop initial dictionary
r = r + 1
If key = "data" Then '<==collection of dictionaries
For Each item In json("data")
headerRow = headerRow + 1
c = 1
For Each key2 In item '<== individual dictionary
If headerRow = 1 Then '<== test to write out headers of symbols info only once
ws.Cells(r, c) = key2
ws.Cells(r + 1, c) = item(key2)
Else
ws.Cells(r + 1, c) = item(key2)
End If
c = c + 1
Next
r = r + 1
Next
Else 'string literal key, value pairs
ws.Cells(r, 1) = key: ws.Cells(r, 2) = json(key)
End If
Next
End Sub
Sample of data in sheet:
Related
I'm looking for an idea to help me extract the data from one cell("data"). When the value from another cell ("id") is for example 11, I want to display the corresponding parsed value from "data" into rows and columns from another Excel-Worksheet.I'm using the library (VBA-JSON v2.3.1 JsonConverter)
I have the following JSON-Object:
{
"Messages":[
{
"internalDeviceId":11,
"rawJson":"{\"temperature\":22.6,\"humidity\":37,\"light\":1,\"motion\":1,\"co2\":640,\"vdd\":3.647}"
},
{
"internalDeviceId":12,
"rawJson":"{\"humidity\":30,\"pressure\":1000,\"CO2\":700,\"vdd\":3.654}"
},
{
"internalDeviceId":13,
"rawJson":"{\"latitude\":47.654,\"longitude\":9.654,\"vdd\":3.432}"
},
{
"internalDeviceId":11,
"rawJson":"{\"temperature\":23.0,\"humidity\":38,\"light\":20,\"motion\":0,\"co2\":665,\"vdd\":3.621}"
},
{
"internalDeviceId":11,
"rawJson":"{\"temperature\":22.1,\"humidity\":35,\"light\":15,\"motion\":1,\"co2\":650,\"vdd\":3.425}"
}
]
}
I got the data from a rest API with a VBA code and that is working. At the moment I get the following information in excel:
My code looks like this:
Dim response2 As String
Dim json1 As Object
Dim ws2 As Worksheet
strUrl = "https://xxxxxxxxxxxx/devices/11/"
Set hReq = CreateObject("MSXML2.XMLHTTP")
With hReq
Set ws2 = Worksheets(3)
.Open "GET", strUrl, False
.SetRequestHeader "Authorization", "Bearer " & apitoken
.Send
response2 = hReq.responseText
Set json1 = JsonConverter.ParseJson(response2)
k = 2
For Each item In json1("Messages")
ws2.Cells(k, 3) = item("externalDeviceId")
ws2.Cells(k, 8) = item("rawJson")
k = k + 1
Next item
End With
I just want to split the information from "data" in rows and columns based on a certain "id" for example in this case 11. The structure from "data" depends on "id". I want to do this in VBA without PowerQuery. I was searching for hours and didn't find a solution.
I know that the item I am returning is, itself, a JSON string. To split the information from it, I create another JSON object. I don't know how I can get the information from data into rows and columns because of the different structures of "data".
How can I access these different values depending on the "id"?
Assuming you will want to handle all id cases being written to same range then you could use a helper dict, initialised with all the possible column headers (keys of rawJson dictionary) and with empty values. As you process each intended row to write out, item("rawJson"), simply overwrite the existing vbNullString values where present in both dictionaries. Keys not present in current row will be left with vbNullString values, due to On Error Resume Next wrapper inside helper function.
If you only care about id = 11 then add in an If ... End If
For Each item In json1
id = item("internalDeviceId")
If id = 11 Then
Set dict = GetHomogenousRow(id, headers, item("rawJson"))
r = r + 1
.Cells(r, 1).Resize(1, dict.Count) = Application.Transpose(dict.Values)
End If
Next
If you are intending to pick up id from the sheet that is also easy enough to incorporate, though I don't know what would stop each call with id of 11 from being identical; unless website updates very rapidly and there were a timestamp field - seems unlikely for basic weather info.
N.B. Not tested. Please provide valid json sample.
Option Explicit
Public Sub WriteOutObservations()
Dim response2 As String, url As String, hReq As Object, apitoken As String
url = "https://xxxxxxxxxxxx/devices/11/"
apitoken = "xyz"
Set hReq = CreateObject("MSXML2.XMLHTTP")
With hReq
.Open "GET", url, False
.SetRequestHeader "Authorization", "Bearer " & apitoken
.Send
response2 = hReq.responseText
End With
Dim headers(), id As Long, json1 As Object
Dim item As Object, r As Long, ws2 As Worksheet
headers = Array("id", "temperature", "humidity", "light", "motion", "co2", "vdd")
Set json1 = JsonConverter.ParseJson(response2)
Set ws2 = ThisWorkbook.Worksheets("Sheet3")
r = 1
With ws2
.Cells(1, 1).Resize(1, UBound(headers) + 1) = headers
For Each item In json1
id = item("internalDeviceId")
Set dict = GetHomogenousRow(id, headers, item("rawJson"))
r = r + 1
.Cells(r, 1).Resize(1, dict.Count) = Application.Transpose(dict.Values)
Next
End With
End Sub
Public Function GetHomogenousRow(ByVal id As Long, ByRef headers As Variant, ByVal inputDict As Scripting.Dictionary) As Scripting.Dictionary
Dim dict As Scripting.Dictionary, i As Long, key As Variant
Set dict = New Scripting.Dictionary
For i = LBound(headers) To UBound(headers)
dict.Add headers(i), vbNullString
Next
dict("id") = id
On Error Resume Next 'ignore where key not present
For Each key In dict.Keys
dict(key) = inputDict(key)
Next
On Error GoTo 0
Set GetHomogenousRow = dict
End Function
I am trying to pull JSON values from a URL that I am working with at the moment. I may have done something like this before but I dont know what I'm missing here.
Here is the URL - https://eu-offering.kambicdn.org/offering/v2018/888/listView/golf.json?lang=en_GB&market=GB&client_id=2&channel_id=1&ncid=1568916879040&useCombined=true
And an image for clarity of what is needed to be extracted.
I ran a test using Tinman's approach as can be found here - How to get, JSON values to Work in VBA-JSON? , but i can't even apply his function, PrintJSONAccessors(), here
Public Sub exceljson()
Dim http As Object
Set http = CreateObject("MSXML2.XMLHTTP")
http.Open "GET",
"https://eu-offering.kambicdn.org/offering/v2018/888/listView/golf.json?lang=en_GB&market=GB&client_id=2&channel_id=1&ncid=1568916879040&useCombined=true", False
http.Send
Dim results As Variant
results = BitfinexTextToArray(http.responseText)
Worksheets(1).Range("A1").Resize(UBound(results), UBound(results,2)).Value = results
MsgBox ("complete")
End Sub
Function BitfinexTextToArray(responseText As String) As Variant
Dim item As Variant, JSON As Object
Dim MaxColumns As Long
Set JSON = ParseJson(responseText)
For Each item In JSON
If item.Count > MaxColumns Then MaxColumns = item.Count
Next
Dim results As Variant
ReDim results(1 To JSON.Count, 1 To MaxColumns)
Dim c As Long, r As Long
For Each item In JSON
r = r + 1
For c = 1 To item.Count
results(r, c) = item(c)
Next
Next
BitfinexTextToArray = results
End Function
I need help with pulling the following item values from each of the JSON "event"
1. "englishName"
2. "participant"
3. "oddsFractional"
NOTE: my example uses the JsonConverter library and requires you to add a reference to the Microsoft Scripting Runtime to access the Dictionary object.
I set up a test file with JSON loaded from your URL above. After parsing the JSON data, the exercise becomes understanding how the various levels are nested and what type of data structure is being used. In your JSON, it's a mix of Collection, Array, and Dictionary in various combinations. My example below shows how you have to stack up these nested references to get the data you're looking for.
Review the information in this answer to understand how the JSON is parsed into a hierarchical data structure.
Option Explicit
Public Sub test()
Dim fileNum As Long
fileNum = FreeFile()
Dim filename As String
filename = "C:\Temp\testdata.json"
Dim jsonInput As String
Open filename For Input As #fileNum
jsonInput = Input$(LOF(fileNum), fileNum)
Close fileNum
Dim json As Object
Set json = ParseJson(jsonInput)
Debug.Print " English Name = " & json("events")(1)("event")("englishName")
Debug.Print " Participant = " & json("events")(1)("betOffers")(1)("outcomes")(2)("participant")
Debug.Print "Odds Fractional = " & json("events")(1)("betOffers")(1)("outcomes")(2)("oddsFractional")
End Sub
An even better solution will be to create an intermediate variable and then loop over the contents in an array (or collection or dictionary).
I'm looking to import all England and Wales Bank Holidays from https://www.gov.uk/bank-holidays.json and add them to a pre-created MS Access recordset (called "TestTable") using the MS Access VBA module. The code below opens and converts the json to a string, and then parses it using the JsonConverter.
This is where I seem to have hit a wall - I can't seem to get the right combo of Dictionaries and Collections to tell the VBA module the structure of the json file (I have no problem with creating a record in Access). After parsing the json, I'm getting one of two errors, most likely because what I think is supposed to be a dictionary (with {} brackets) and what I think is supposed to be a collection (with [] brackets) give me errors.
Option Explicit
Sub ImportBH()
Dim Parsed As Dictionary
Dim rsT As DAO.Recordset
Dim jsonStr As String
Dim dictionaryKey, var1 As Variant
Dim initialCollection As Collection
Set rsT = CurrentDb.OpenRecordset("TestTable")
Dim httpobject As Object
Set httpobject = CreateObject("MSXML2.XMLHTTP")
httpobject.Open "GET", "https://www.gov.uk/bank-holidays.json", False
httpobject.Send
jsonStr = httpobject.responsetext
Set Parsed = ParseJson(jsonStr) 'parse json data
If I now use the line:
For Each dictionaryKey In Parsed("england-and-wales")
Then at the end of the "item" function in JsonConverter, I get a Run-time error 438: Object doesn't support this property or method.
On the other hand, if I use the line:
For Each dictionaryKey In Parsed.Keys
Then it works (using the "Keys" function in JsonConverter), and when I hover over "Parsed.Keys", it gives me "england-and-wales". However, at the first line of the following code, I get a Run-time error 13: Type mismatch.
Set initialCollection = dictionaryKey("events")
With rsT
.AddNew
![Title] = var1("title")
![Datex] = var1("date")
![Notes] = var1("notes")
.Update
End With
Next
End Sub
I've tried the solutions (and others similar) in these links.
https://github.com/VBA-tools/VBA-Web/issues/134 - I'm aware this is for exporting json and not importing, but I thought the syntax might help, as Tim Hall has replied himself. Unfortunately, The ".Data" property doesn't appear or work for me :(
VBA-Json Parse Nested Json - When trying to apply this to the UK Bank Holidays json, I get Run-time error 13 again.
https://github.com/VBA-tools/VBA-Web/issues/329 - If I try, for example:
Debug.Print Parsed(dictionaryKey)
Then after then "item" function in JsonConverter, I get a Run-time error 449: Argument not optional.
https://github.com/VBA-tools/VBA-Web/issues/260 - I can't get to the stage to create a collection to use ".Count" to make this work.
If anyone has achieved this before in VBA, or might be able to offer a hand, it would be very much appreciated!
Start with learning how to read the json structure. You can paste the json string in a json viewer. You then get a nice view of the structure. In VBA JSON the [] denote a collection you can For Each over or access by index, and the {} denotes a dictionary you can For Each the keys of, or access by specific key.
If you put your json into a viewer you should be reading it something like as follows:
Excel version for use as template:
Accessing all items:
The following shows one way of emptying the entire json into an array (you could amend for adding to recordset?)
Option Explicit
Public Sub EmptyJsonIntoArray()
Dim json As Object, r As Long, c As Long, results(), counter As Long
With CreateObject("MSXML2.XMLHTTP")
.Open "GET", "https://www.gov.uk/bank-holidays.json", False
.Send
Set json = JsonConverter.ParseJson(.responsetext) 'dictionary with 3 keys
End With
Dim key As Variant, innerKey As Variant, col As Collection
Dim division As String, headers(), item As Object, arr()
arr = json.keys
headers = json(arr(LBound(arr)))("events").item(1).keys 'take first innermost dictionary keys as headers for output
'oversize array as number of events can vary by division
ReDim results(1 To 1000, 1 To UBound(headers) + 2) '4 is the number of keys for each event level dictionary. +1 so can have _
division included as first column in output and +1 to move from 0 based headers array to 1 based results
r = 1 'leave first row for headers
results(1, 1) = "Division"
For c = LBound(headers) To UBound(headers)
results(1, c + 2) = headers(c) 'write out rest of headers to first row
Next
For Each key In json.keys 'england-and-wales etc. division
division = key
For Each item In json(division)("events") 'variable number of events dictionaries within collection
r = r + 1: c = 2 'create a new row for event output. Set column to 2 (as position 1 will be occupied by division
results(r, 1) = division
For Each innerKey In item.keys 'write out innermost dictionary values into row of array
results(r, c) = item(innerKey)
c = c + 1
Next
Next
Next
'transpose array so can redim preserve the number of rows (now number of columns) to only required number based on current value of r
results = Application.Transpose(results)
ReDim Preserve results(1 To UBound(headers) + 2, 1 To r)
results = Application.Transpose(results) 'transpose array back
'STOP '<== View array
End Sub
Sample of results contents:
Access:
From feedback by OP. With Access there is no Application.Transpose. Instead array can be passed to the following functionsource. However, the array must then be 0 based that is passed.
Public Function TransposeArray(myarray As Variant) As Variant
Dim X As Long
Dim Y As Long
Dim Xupper As Long
Dim Yupper As Long
Dim tempArray As Variant
Xupper = UBound(myarray, 2)
Yupper = UBound(myarray, 1)
ReDim tempArray(Xupper, Yupper)
For X = 0 To Xupper
For Y = 0 To Yupper
tempArray(X, Y) = myarray(Y, X)
Next Y
Next X
TransposeArray = tempArray
End Function
Access version as appended by OP:
In addition to TransposeArray above (edited below to work in this case), here's the full code for Access:
Option Compare Database
Option Explicit
Public Sub UpdateBankHolidays()
Dim dbs As DAO.Database
Dim tBH As Recordset
Dim i, r, c As Long
Set dbs = CurrentDb
'Set recordset variable as existing table (in this case, called "z_BankHolidays")
Set tBH = dbs.OpenRecordset("z_BankHolidays")
'Download and parse json
Dim json As Object, results(), counter As Long
With CreateObject("MSXML2.XMLHTTP")
.Open "GET", "https://www.gov.uk/bank-holidays.json", False
.Send
Set json = ParseJson(.responsetext) 'dictionary with 3 keys
End With
Dim key As Variant, innerKey As Variant, col As Collection
Dim division As String, headers(), item As Object, arr()
arr = json.Keys
headers = json(arr(LBound(arr)))("events").item(1).Keys 'take first innermost dictionary keys as headers for output
'oversize array as number of events can vary by division
ReDim results(1 To 1000, 1 To UBound(headers) + 2) '4 is the number of keys for each event level dictionary. +1 so can have _
division included as first column in output and +1 to move from 0 based headers array to 1 based results
r = 1 'leave first row for headers
results(1, 1) = "Division"
For c = LBound(headers) To UBound(headers)
results(1, c + 2) = headers(c) 'write out rest of headers to first row
Next
For Each key In json.Keys 'england-and-wales etc. division
division = key
For Each item In json(division)("events") 'variable number of events dictionaries within collection
r = r + 1: c = 2 'create a new row for event output. Set column to 2 (as position 1 will be occupied by division
results(r, 1) = division
For Each innerKey In item.Keys 'write out innermost dictionary values into row of array
results(r, c) = item(innerKey)
c = c + 1
Next
Next
Next
'transpose array so can redim preserve the number of rows (now number of columns) to only required number based on current value of r
results = TransposeArray(results)
ReDim Preserve results(0 To UBound(results), 0 To r)
results = TransposeArray(results) 'transpose array back
'Clear all existing bank holidays from recordset
dbs.Execute "DELETE * FROM " & tBH.Name & ";"
'Insert array results into tBH recordset, transforming the date into a date value using a dd/mmm/yyyy format (in the array they are currently yyyy-mm-dd)
For i = 1 To r
If results(i, 1) = "england-and-wales" Then
dbs.Execute " INSERT INTO " & tBH.Name & " " _
& "(Title,Holiday,Notes) VALUES " _
& "('" & results(i, 2) & "', " & _
"'" & DateValue(Right(results(i, 3), 2) & "/" & Format("20/" & Mid(results(i, 3), 6, 2) & "/2000", "mmm") & "/" & Left(results(i, 3), 4)) & "', " & _
"'" & results(i, 4) & "'" & _
");"
End If
Next
'Finish
MsgBox "Bank Holidays updated."
End Sub
It's also worth noting that I (OP) had to change X and Y in the TransposeArray to start from 1, not 0 (even though, as noted above and in comments, subsequently redimming it must be based at 0). I.e.:
Public Function TransposeArray(myarray As Variant) As Variant
Dim X As Long
Dim Y As Long
Dim Xupper As Long
Dim Yupper As Long
Dim tempArray As Variant
Xupper = UBound(myarray, 2)
Yupper = UBound(myarray, 1)
ReDim tempArray(Xupper, Yupper)
For X = 1 To Xupper
For Y = 1 To Yupper
tempArray(X, Y) = myarray(Y, X)
Next Y
Next X
TransposeArray = tempArray
End Function
I'm trying to access in VBA to over 508 "tank_id"s from a JSON file as you can see here.
I'm using cStringBuilder, cJSONScript and JSONConverter to parse the JSON file.
My main issue is that I can't pass threw all those ids because I don't know how to get the "1" "33" "49" "81" that are without names.
Here si the code I tried to get them, without success.
Const myurl2 As String = "https://api.worldoftanks.eu/wot/encyclopedia/vehicles/?application_id=demo&fields=tank_id"
Sub List_id_vehicules()
Dim strRequest
Dim xmlHttp: Set xmlHttp = CreateObject("msxml2.xmlhttp")
Dim response As Object
Dim rows As Integer
Dim counter As Integer
Dim j As String
Dim k As Integer: k = 2
Dim url As String
url = myurl2
xmlHttp.Open "GET", url, False
xmlHttp.setRequestHeader "Content-Type", "text/xml"
xmlHttp.send
While Not xmlHttp.Status = 200 '<---------- wait
Wend
Set response = ParseJson(xmlHttp.ResponseText)
rows = response("meta")("count")
For counter = 1 To rows
j = counter
Dim yop As String
yop = "data[" & j & "][" & j & "]"
Sheets(2).Cells(1 + counter, 1).Value = response('data[counter]')['tank_id']
Next counter
END Sub
Could someone help me ?
The JSONConverter essentially parses the JSON text string into a set of nested Dictionary objects. So when the ParseJson function returns an Object, it's really a Dictionary. Then, when you access response("meta"), the "meta" part is the Key to the Dictionary object. It's the same thing as you nest down through the JSON.
So when you try to access response("data")("3137"), you're accessing the Dictionary returned by response("data") with the key="3137". Now the trick becomes how to get all the Keys from the response("data") object.
Here's a sample bit of code to illustrate how you can list all the tank IDs in the JSON data section:
Option Explicit
Sub ListVehicleIDs()
Const jsonFilename As String = "C:\Temp\tanks.json"
Dim fileHandle As Integer
Dim jsonString As String
fileHandle = FreeFile
Open jsonFilename For Input As #fileHandle
jsonString = Input$(LOF(fileHandle), #fileHandle)
Close #fileHandle
Dim jsonObj As Object
Set jsonObj = ParseJson(jsonString)
Dim tankCount As Long
tankCount = jsonObj("meta")("count")
Dim tankIDs As Dictionary
Set tankIDs = jsonObj("data")
Dim tankID As Variant
For Each tankID In tankIDs.keys
Debug.Print "Tank ID = " & tankID
Next tankID
End Sub
I keep receiving a "type mismatch error" (indicating that its not an array?) at:
Sub FillTaxiInfo
For i = 0 To UBound(data("prices")) - 1
The code is attempting to parse JSON from (see "prices" below):
{"id":1,"prices":[{"name":"expressTaxi","fare":{"fareType":"standard", "base":"$2.50"...}}
When I place a breakpoint and inspect "prices", it tells me that the 'Value' is Expression not defined in context and 'Type' is Empty.
Any other suggestions for improvement would be much appreciated.
My full code:
Option Explicit
Sub Run()
Dim myUrls As Variant
myUrls = Array("URL1, URL2, URL3")
FillMultipleCityInfo myUrls, ActiveWorkbook
End Sub
Function GetJson(ByVal url As String) As Dictionary
With New WinHttpRequest
.Open "GET", url
.Send
Set GetJson = JsonConverter.ParseJson(.ResponseText)
End With
End Function
Sub FillTaxiInfo(data As Dictionary, sheet As Worksheet)
Dim i As Integer, taxi As Dictionary
For i = 0 To UBound(data("prices")) - 1
Set taxi = data("prices")(i)
If taxi.Exists("name") Then
sheet.Cells(i, 1) = taxi("name")
sheet.Cells(i, 2) = taxi("fare")("fareType")
End If
Next i
End Sub
Sub FillMultipleCityInfo(urls As Variant, book As Workbook)
Dim i As Integer, data As Dictionary, sheet As Worksheet
For i = 0 To UBound(urls) - 1
Set data = GetJson(urls(i))
Set sheet = book.Sheets(i + 1)
FillTaxiInfo data, sheet
Next i
End Sub
You are trying to receive the UBound() of an Dictionary data structure and not an Array. UBound() will only function on an Array.
Instead it appears you want to iterate over the keys of a Dictionary. Here is a small example how to do this.
Public Sub Dict_Iter()
Dim key As Variant 'Even though the key is a string --
'Objects/Variant are needed in a For Each Loop
Dim dict As New Dictionary
'Add several items to the dictionary
With dict
.Add "a", "a"
.Add "b", "b"
.Add "c", "c"
End With
'Iterate over the keys
For Each key In dict.Keys()
Debug.Print dict(key)
Next
End Sub