I am trying to access nested JSON values that come back from the API that I am working with at the moment. There seem to be no field names to use in this JSON, making it very difficult to follow most examples online.
API URL - CLICK HERE
I am using VBA-JSON through this process, and I've got it to successfully display "responseText" in MsgBox.
I am looking for a way to make this code work.
Public Sub exceljson()
Dim http As Object, JSON As Object, i As Integer
Set http = CreateObject("MSXML2.XMLHTTP")
http.Open "GET", "https://api.bitfinex.com/v2/candles/trade:5m:tEOSUSD/hist?start=1535760000000&end=1538265600000&sort=1", False
http.Send
Set JSON = ParseJson(http.responseText)
i = 2
For Each Item In JSON
Sheets(1).Cells(i, 1).Value = Item("one") ' Items reference as an example
Sheets(1).Cells(i, 2).Value = Item("two")
Sheets(1).Cells(i, 3).Value = Item("three")
Sheets(1).Cells(i, 4).Value = Item("four")
Sheets(1).Cells(i, 5).Value = Item("five")
i = i + 1
Next
MsgBox ("complete")
End Sub
In my answer to Using VBA and VBA-JSON to access JSON data from Wordpress API
, I wrote a function, PrintJSONAccessors(), which breaks down how to access the data in a JSON structure.
Checking the JSON object in the Locals Window reveals that it consists of a collection of collections.
Checking the TypeName of the item in the Immediate Window also reveals that item is indeed a collection'
?TypeName(Item)
Collection
PrintJSONAccessors JSON, "?JSON"
The code will output the correct way to access the data
Here is how you can access the items of the Collection
For Each Item In JSON
Sheets(1).Cells(i, 1).Value = Item(1) ' Items reference as an example
Sheets(1).Cells(i, 2).Value = Item(2)
Sheets(1).Cells(i, 3).Value = Item(3)
Sheets(1).Cells(i, 4).Value = Item(4)
Sheets(1).Cells(i, 5).Value = Item(5)
i = i + 1
Next
I would write a function to convert the JSON data into an Array
Public Sub exceljson()
Dim http As Object
Set http = CreateObject("MSXML2.XMLHTTP")
http.Open "GET", "https://api.bitfinex.com/v2/candles/trade:5m:tEOSUSD/hist?start=1535760000000&end=1538265600000&sort=1", 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
Related
I have a json like with this format
[{"ts_id": "96643010","rows": "64","columns":"Timestamp,Value", "data": [["2021-09-01T11:00:00.000+07:00",206.95],["2021-09-01T12:00:00.000+07:00",206.96],["2021-09-01T13:00:00.000+07:00",206.97],["2021-09-01T14:00:00.000+07:00",206.95],["2021-09-01T15:00:00.000+07:00",206.92],["2021-09-01T16:00:00.000+07:00",206.89],["2021-09-01T17:00:00.000+07:00",206.86],["2021-09-01T18:00:00.000+07:00",206.83],["2021-09-01T19:00:00.000+07:00",206.80],["2021-09-01T20:00:00.000+07:00",206.77],["2021-09-01T21:00:00.000+07:00",206.74],["2021-09-01T22:00:00.000+07:00",206.71],["2021-09-01T23:00:00.000+07:00",206.68],["2021-09-02T00:00:00.000+07:00",206.65],["2021-09-02T01:00:00.000+07:00",206.63],["2021-09-02T02:00:00.000+07:00",206.65],["2021-09-02T03:00:00.000+07:00",206.67],["2021-09-02T04:00:00.000+07:00",206.69],["2021-09-02T05:00:00.000+07:00",206.71],["2021-09-02T06:00:00.000+07:00",206.73],["2021-09-02T07:00:00.000+07:00",206.75],["2021-09-02T08:00:00.000+07:00",206.76],["2021-09-02T09:00:00.000+07:00",206.77],["2021-09-02T10:00:00.000+07:00",206.78],["2021-09-02T11:00:00.000+07:00",206.79],["2021-09-02T12:00:00.000+07:00",206.80],["2021-09-02T13:00:00.000+07:00",206.81],["2021-09-02T14:00:00.000+07:00",206.82],["2021-09-02T15:00:00.000+07:00",206.83],["2021-09-02T16:00:00.000+07:00",206.83],["2021-09-02T17:00:00.000+07:00",206.83],["2021-09-02T18:00:00.000+07:00",206.83],["2021-09-02T19:00:00.000+07:00",206.83],["2021-09-02T20:00:00.000+07:00",206.83],["2021-09-02T21:00:00.000+07:00",206.84],["2021-09-02T22:00:00.000+07:00",206.85],["2021-09-02T23:00:00.000+07:00",206.86],["2021-09-03T00:00:00.000+07:00",206.87],["2021-09-03T01:00:00.000+07:00",206.89],["2021-09-03T02:00:00.000+07:00",206.91],["2021-09-03T03:00:00.000+07:00",206.93],["2021-09-03T04:00:00.000+07:00",206.95],["2021-09-03T05:00:00.000+07:00",206.96],["2021-09-03T06:00:00.000+07:00",206.97],["2021-09-03T07:00:00.000+07:00",206.98],["2021-09-03T08:00:00.000+07:00",207.00],["2021-09-03T09:00:00.000+07:00",207.02],["2021-09-03T10:00:00.000+07:00",207.04],["2021-09-03T11:00:00.000+07:00",207.06],["2021-09-03T12:00:00.000+07:00",207.08],["2021-09-03T13:00:00.000+07:00",207.11],["2021-09-03T14:00:00.000+07:00",207.14],["2021-09-03T15:00:00.000+07:00",207.17],["2021-09-03T16:00:00.000+07:00",207.18],["2021-09-03T17:00:00.000+07:00",207.19],["2021-09-03T18:00:00.000+07:00",207.20],["2021-09-03T19:00:00.000+07:00",207.20],["2021-09-03T20:00:00.000+07:00",207.20],["2021-09-03T21:00:00.000+07:00",207.20],["2021-09-03T22:00:00.000+07:00",207.19],["2021-09-03T23:00:00.000+07:00",207.18],["2021-09-04T00:00:00.000+07:00",207.17],["2021-09-04T01:00:00.000+07:00",207.18],["2021-09-04T07:00:00.000+07:00",207.30]]}]
Blockquote
I have tried to get this data with VBA but unsuccess, somebody can help me with VBA code to get data from "data".
This the code i have used:
Public Sub exceljson()
Dim http As Object, JSON As Object, i As Integer
Set http = CreateObject("MSXML2.XMLHTTP")
http.Open "GET", "https://cdh.vnmha.gov.vn/KiWIS/KiWIS?service=kisters&type=queryServices&request=getTimeseriesValues&datasource=0&format=dajson&ts_id=96643010&period=P3D", False
http.Send
Set JSON = ParseJson(http.responseText)
i = 2
For Each Item In JSON
Sheets(1).Cells(i, 1).Value = Item("data")
i = i + 1
Next
MsgBox ("complete")
End Sub
I receive run-time error '13' Type mismatch when trying to import some data via IEX API using JSON.
I receive the error when setting the values for the cells in the For Each loop.
Here's a link to view the API data:
https://api.iextrading.com/1.0/stock/aapl/financials?period=annual
Sub getFinancials()
'Write to ws
Dim ws As Worksheet
Set ws = Sheets("Financials")
Dim ticker As String
ticker = ws.Range("P7").value
Dim lastrow As Long
lastrow = ws.Cells(Rows.Count, "A").End(xlUp).Row
'Clear Range
ws.Range("A1:L" & lastrow).Clear
'Array Column Headers
Dim myarray As Variant
myarray = Array("reportDate", "grossProfit", "costOfRevenue", "operatingRevenue", "totalRevenue", "operatingIncome", "netIncome", "researchAndDevelopment", "operatingExpense", "currentAssets", "totalAssets", "totalLiabilities", "currentCash", "currentDebt", "totalCash", "totalDebt", "shareholderEquity", "cashChange", "cashFlow", "operatingGainsLosses")
Arrsize = UBound(myarray) - LBound(myarray) + 1
Dim rngTarget As Range
Set rngTarget = ws.Range(Cells(2, 1), Cells(Arrsize + 1, 1))
rngTarget.value = Application.Transpose(myarray)
'Send web request for API Data
u = "https://api.iextrading.com/1.0/stock/" & ticker & "/financialsperiod=annual"
' https://api.iextrading.com/1.0/stock/aapl/financials?period=annual
Set myrequest = CreateObject("WinHttp.WinHttpRequest.5.1")
myrequest.Open "Get", u
myrequest.Send
'Parse JSON
Dim JSON As Object
Set JSON = JsonConverter.ParseJson(myrequest.ResponseText)
'Get # of Objects in Array
Dim arrayLen As Integer
arrayLen = JSON.Count
'Loop through Elements
Dim element As Variant
Dim x, y, r As Integer
r = 2
y = 2
x = 1
While x < arrayLen + 1
For Each element In myarray
ws.Cells(r, y).value = JSON(2)(element)
y = y + 1
Next element
y = 2
x = x + 1
r = r + 1
Wend
End Sub
I just ran the JSON through the converter and this is the structure that I get:
-Dictionary(2 items)
--Collection(4 items)
---Dictionary(20 items)
You need to extract the data accordingly. Collections can be looped through with a simple for each loop. Dictionarys can be looped through with the following structure.
Option Explicit
Sub PrintFinancialReports()
Dim apiURL As String
apiURL = "https://api.iextrading.com/1.0/stock/aapl/financials?period=annual"
Dim myrequest As WinHttpRequest
Set myrequest = New WinHttpRequest
myrequest.Open "Get", apiURL
myrequest.Send
Debug.Print myrequest.ResponseText ' print received JSON to check if it is valid
Dim FinancialReportQuery As Dictionary
Set FinancialReportQuery = JsonConverter.ParseJson(myrequest.ResponseText)
Debug.Print FinancialReportQuery.Item("symbol")
Dim Reports As Collection
Set Reports = FinancialReportQuery.Item("financials")
Dim report As Dictionary
For Each report In Reports
Dim reportContentKey As Variant '<-- variant is needed to loop a dictionary
For Each reportContentKey In report
Debug.Print reportContentKey, report.Item(reportContentKey)
Next reportContentKey
Next report
End Sub
Hope this helps
I have a multidimensional JSON array returned via a web request (http://www.coincap.io/history/365day/BTC). I want to cycle through the 2nd entry and retrieve its nested values.
If this was a normal array, I'd use:
For Each item In response
logic, logic, logic
currentRow = currentRow + 1
Next
This web request returns a JSON-response with 3 entries: market_cap, price, and volume. I just want to cycle through response(1) and get the price values. Each entry in price contains two keys, 0 and 1.
I would imagine that I could accomplish this by doing
For Each item in response(1)
Cells(currentRow, 1).Value = item(0)
Cells(currentRow, 2).Value = item(1)
currentRow = currentRow + 1
Next
I've also considered For Each item in response("price"). Neither works.
Sub Tester()
Dim json As String
Dim sc As Object
Dim o, n, i, p
Set sc = CreateObject("scriptcontrol")
sc.Language = "JScript"
json = HttpGet("http://www.coincap.io/history/365day/BTC")
sc.Eval "var obj=(" & json & ")" 'evaluate the json response
'add a couple of accessor functions
sc.AddCode "function numPrices(){return obj.price.length;}"
sc.AddCode "function getPrice(i){return obj.price[i];}"
n = sc.Run("numPrices")
For i = 0 To n - 1
p = Split(sc.Run("getPrice", i), ",")
Debug.Print i, p(0), p(1)
Next i
End Sub
Function HttpGet(url As String) As String
Dim oHTML As Object
Set oHTML = CreateObject("Microsoft.XMLHTTP")
With oHTML
.Open "GET", url, False
.send
HttpGet = .responsetext
End With
End Function
I am looking for a loop function/syntax that will allow my loop to cease once the website I am pulling JSON arrays from has no additional arrays left to parse (variable / unknowable number of arrays).
Thank you for the insight.
sheetCount = 1
i = 1
urlArray = Array("URL array list")
Dim MyRequest As Object
Set MyRequest = CreateObject("WinHttp.WinHttpRequest.5.1")
Dim MyUrls
MyUrls = urlArray
Dim k As Long
Dim Json As Object
For k = LBound(MyUrls) To UBound(MyUrls)
With MyRequest
.Open "GET", MyUrls(k)
.Send
Set Json = JsonConverter.ParseJson(.ResponseText)
Do Until ''[NEED HELP HERE]
Sheets("Sheet" & sheetCount).Cells(i, 1) = Json("cars")(i)("carType")
Sheets("Sheet" & sheetCount).Cells(i, 2) = Json("cars")(i)("fare")("carprice")
i = i + 1
Loop
End With
sheetCount = sheetCount + 1
Next
You are missing the UBound function.
Other notes
No code without Option Explicit, period. No exceptions.
Make small functions that do one thing only.
Add references to the libraries you use instead of using CreateObject. It will make your life a lot easier because this way you get compile-time type checking and Intellisense.
It's safer to use the Exists() method to check if a dictionary key exists before you try to access it. Trying to access a non-existing key will throw a run-time error.
I'm silently assuming that you are using https://github.com/VBA-tools/VBA-JSON.
This should be close enough:
Option Explicit
Function GetJson(ByVal url As String) As Dictionary
With New WinHttpRequest ' see http://stackoverflow.com/a/3119794/18771
.Open "GET", url
.Send
Set GetJson = JsonConverter.ParseJson(.ResponseText)
End With
End Function
Sub FillCarInfo(data As Dictionary, sheet As Worksheet)
Dim i As Integer, car As Dictionary
For i = 0 To UBound(data("cars")) - 1
Set car = data("cars")(i)
' you probably should use If car.Exists("carType") Then
sheet.Cells(i, 1) = car("carType")
sheet.Cells(i, 1) = car("fare")("carprice")
Next i
End Sub
Sub FillMultipleCarInfo(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)
FillCarInfo data, sheet
Next i
End Sub
Usage
Dim myUrls As Variant
myUrls = Array("URL array list")
FillMultipleCarInfo myUrls, ActiveWorkbook
I'm making some sort of football database where I would input data using a userform and where I want to retrieve data from my excel database.
I have a worksheet named: "wedstrijden" This worksheet contain the columns: Date, HomeTeam, AwayTeam, HomeScore,AwayScore, HomeOdds and AwayOdds
My other worksheet is named: "ingevenuitslagen" This worksheet contains my userform called UitslagenIngeven
Using the code below I'm able to input my data from the userform to my "wedstrijden" worksheet
Private Sub putAway_Click()
Dim ingevenuitslagen As Worksheet
Set ingevenuitslagen = ThisWorkbook.Sheets("wedstrijden")
NextRow = ingevenuitslagen.Cells(Rows.Count, 1).End(xlUp).Row + 1
ingevenuitslagen.Cells(NextRow, 1) = CDate(date_txt.Text)
ingevenuitslagen.Cells(NextRow, 2) = UitslagenIngeven.cboHomeTeam
ingevenuitslagen.Cells(NextRow, 3) = UitslagenIngeven.cboAwayTeam
ingevenuitslagen.Cells(NextRow, 4) = UitslagenIngeven.cboHScore
ingevenuitslagen.Cells(NextRow, 5) = UitslagenIngeven.cboAScore
ingevenuitslagen.Cells(NextRow, 6) = Val(UitslagenIngeven.hodds_txt.Text)
ingevenuitslagen.Cells(NextRow, 7) = Val(UitslagenIngeven.aodds_txt.Text)
End Sub
But this is only to put away 1 row. I would like to make the possibility to put away 10 or 15 rows at once. So I would make a userform with the possibility to put away 20 rows BUT it should be able to put away only those rows that are filled in.
Is this possible? And how should I adjust my userform? Can I just copy the text and combobox areas ?
How to work with a Data Array
You'll need to create a new button, you'll have :
one for adding the data set to the data array (here CommandButton1) and
one to add the data array to the data base (here CommandButton2).
I also prefer to work with a Named Range for the Data Base, here it is called Db_Val but you can rename this to fit your needs! ;)
Code to place in the UserForm to fill the data array :
Public ingevenuitslagen As Worksheet
Public DataA() '----These lines should be at the top of the module
'----Code to Set the dimension of the Data array
Private Sub UserForm_Initialize()
Dim DataA(7, 0)
Set ingevenuitslagen = ThisWorkbook.Sheets("wedstrijden")
'----Rest of your code
End Sub
'----Code to add a data set to the data array
Private Sub CommandButton1_Click()
UnFilter_DB '----See below procedure
DataA(1) = CDate(date_txt.Text)
DataA(2) = UitslagenIngeven.cboHomeTeam
DataA(3) = UitslagenIngeven.cboAwayTeam
DataA(4) = UitslagenIngeven.cboHScore
DataA(5) = UitslagenIngeven.cboAScore
DataA(6) = Val(UitslagenIngeven.hodds_txt.Text)
DataA(7) = Val(UitslagenIngeven.aodds_txt.Text)
ReDim Preserve DataA(LBound(DataA, 1) To UBound(DataA, 1), LBound(DataA, 2) To UBound(DataA, 2) + 1)
End Sub
'----Code to sent the data array to the DB
Private Sub CommandButton2_Click()
ReDim Preserve DataA(LBound(DataA, 1) To UBound(DataA, 1), LBound(DataA, 2) To UBound(DataA, 2) - 1)
SetData DataA
End Sub
Procedure to print in the database the data array that you pass from the user form :
Here the data base is the Named Range Db_Val in ingevenuitslagen sheet
Public Sub SetData(ByVal Data_Array As Variant)
Dim DestRg As Range, _
A()
'----Find the last row of your DataBase
Set DestRg = ingevenuitslagen.Range("Db_Val").Cells(ingevenuitslagen.Range("Db_Val").Rows.Count, 1)
'----Print your array starting on the next row
DestRg.Offset(1, 0).Resize(UBound(Data_Array, 1), UBound(Data_Array, 2)).Value = Data_Array
End Sub
Sub to unfilter the DB you are working with :
Public Sub UnFilter_DB()
'----Use before "print" array in sheet to unfilter DB to avoid problems (always writing on the same row if it is still filtered)
Dim ActiveS As String, CurrScreenUpdate As Boolean
CurrScreenUpdate = Application.ScreenUpdating
Application.ScreenUpdating = False
ActiveS = ActiveSheet.Name
ingevenuitslagen.Activate
ingevenuitslagen.Range("A1").Activate
ingevenuitslagen.ShowAllData
DoEvents
Sheets(ActiveS).Activate
Application.ScreenUpdating = CurrScreenUpdate
End Sub
Good day all.
I have this same challenge. Mine is to be able to place a Customer's Orders. With the code I have I can only place one product per order at a time for the customer. I want to be able to place multiple products per order for one customer at the same time in a Userform and it will update multiple rows. The code below can only update one row with one product in a row for one customer:
Private Sub cmdAdd_Click()
Dim lRow As Long
Dim ws As Worksheet
lRow = ws.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
With ws
.Cells(lRow, 1).Value = Me.Data1.Value
.Cells(lRow, 2).Value = Me.Data2.Value
.Cells(lRow, 3).Value = Me.Data3.Value
.Cells(lRow, 4).Value = Me.Data4.Value
.Cells(lRow, 5).Value = Me.Data5.Value
.Cells(lRow, 6).Value = Me.Data6.Value
.Cells(lRow, 7).Value = Me.Data7.Value
.Cells(lRow, 8).Value = Me.Data8.Value
.Cells(lRow, 9).Value = Me.Data9.Value
.Cells(lRow, 10).Value = Me.Data10.Value
End With
End Sub
The above can only update One product per customer. A customer could place order for more than one product.