I have the following json file with multiple Descriptions and Customers (not mydata but this is the general structure).
I would like a fast way to find out which customers have a specific module.
For example, the customers which have the AD Module are Customer3,Customer4 (valid are only rows in CustomersDescs and not in 'ALL')
{
"Descriptions": {
"AA": "AA-Module1",
"AD": "AD-Module2",
"AL": "AL-Module3",
"AAB": "AAB-Module4",
"AAC": "AAC-Module5",
"CE": "CE-Module6",
"CL": "CL-Module7"
},
"WebServices": {
"CA": "WS1",
"CB": "WS2",
"CL": "WS2",
"DB": "WS3",
"UA": "WS4"
},
"CustomersDescs": {
"ALL": [
"AA",
"AD",
"AL",
"AAB",
"AAC",
"CE",
"CL"
],
"Customer1": [
"AA",
"AAC"
],
"Customer2": [
"AA",
"CE"
],
"Customer3": [
"AA",
"CE",
"AD",
"CL"
],
"Customer4": [
"AA",
"CE",
"AD",
"CL"
]
}
}
Is there any way to retrieve this info ?
Thanks in advance
The below example shows how to parse JSON and get the data which customers have a specific module. Import JSON.bas module into the VBA project for JSON processing. Put the below code into VBA Project standard module:
Option Explicit
Sub TestModulesDistribution()
Dim sJSONString As String
Dim vJSON As Variant
Dim sState As String
Dim oModules As Object
Dim sCustomer As Variant
Dim sModule As Variant
' Read JSON content
' Put sourse JSON string to "\source.json" file in ASCII or Unicode charset
sJSONString = ReadTextFile(ThisWorkbook.Path & "\source.json", -2)
' Process JSON
JSON.Parse sJSONString, vJSON, sState
Set vJSON = vJSON("CustomersDescs")
Set oModules = CreateObject("Scripting.Dictionary")
vJSON.Remove "ALL"
For Each sCustomer In vJSON
For Each sModule In vJSON(sCustomer)
If Not oModules.Exists(sModule) Then Set oModules(sModule) = CreateObject("Scripting.Dictionary")
oModules(sModule)(sCustomer) = ""
Next
Next
' Output result for example
For Each sModule In oModules
Debug.Print sModule
Debug.Print vbTab & Join(oModules(sModule).Keys(), vbCrLf & vbTab)
Next
End Sub
Function ReadTextFile(sPath As String, lFormat As Long) As String
' lFormat -2 - System default, -1 - Unicode, 0 - ASCII
With CreateObject("Scripting.FileSystemObject").OpenTextFile(sPath, 1, False, lFormat)
ReadTextFile = ""
If Not .AtEndOfStream Then ReadTextFile = .ReadAll
.Close
End With
End Function
Put your JSON to the file in ASCII or Unicode charset to the same folder as the workbook, and name it source.json, then run TestModulesDistribution(). After processing, the example output for me is as follows:
AA
Customer1
Customer2
Customer3
Customer4
AAC
Customer1
CE
Customer2
Customer3
Customer4
AD
Customer3
Customer4
CL
Customer3
Customer4
You can access to oModules dictionary items by module names, and get sub dictionaries, each of them contains customer names as keys for that particular module name.
BTW, the similar approach applied in other answers.
Related
I am trying to import a json file to EXCEL using VBA code but I neither want to use a GitHub project nor use Power Query but I am not able to get any proper reference on how to do it. The json string looks like this:
{
"menu": "food",
"open": "true",
"order": "true",
"food": [
{
"name": "burger",
"type": "saucy",
"id": 1,
"available": true,
"price": "3$"
},
{
"name": "pizza",
"type": "spicy",
"id": 2,
"available": true,
"price": "2$"
}
]
}
My requirement is to show it in excel with column headers as the key and the values in rows like this:
name
type
id
available
price
burger
saucy
1
true
3$
pizza
spicy
2
true
2$
This is a Regex solution which only work specifically to your JSON, the key value in your JSON file must be exactly the same as what you have provided in the question.
Your posted JSON is invalid currently as price does not have quotes so please double check and use the correct regex pattern in the code below:
Private Sub ParseFoodJSON()
Dim jsontxt As String
jsontxt = OpenTxtFile("D:/TestJSON.txt") 'Change to your JSON file path
Dim regex As Object
Set regex = CreateObject("VbScript.RegExp")
regex.Global = True
regex.Pattern = """name"":[\s]{0,}""([\w\d\s]{1,})"",[\s]{0,}""type"":[\s]{0,}""([\w\d\s]{1,})"",[\s]{0,}""id"":([\w\d\s]{1,}),[\s]{0,}""available"":([\w\d\s]{1,}),[\s]{0,}""price"":""([\w\d\s$]{1,})"""
'Use below regex if your price key really does not have quotes
'regex.Pattern = """name"":[\s]{0,}""([\w\d\s]{1,})"",[\s]{0,}""type"":[\s]{0,}""([\w\d\s]{1,})"",[\s]{0,}""id"":([\w\d\s]{1,}),[\s]{0,}""available"":([\w\d\s]{1,}),[\s]{0,}price:""([\w\d\s$]{1,})"""
If regex.test(jsontxt) Then
Dim regexColl As Object
Set regexColl = regex.Execute(jsontxt)
Dim foodArr() As Variant
ReDim foodArr(1 To regexColl.Count + 1, 1 To 5) As Variant
foodArr(1, 1) = "name"
foodArr(1, 2) = "type"
foodArr(1, 3) = "id"
foodArr(1, 4) = "available"
foodArr(1, 5) = "price"
Dim i As Long
Dim foodIndex As Long
For i = 0 To regexColl.Count - 1
foodIndex = i + 2
foodArr(foodIndex, 1) = regexColl(i).SubMatches(0)
foodArr(foodIndex, 2) = regexColl(i).SubMatches(1)
foodArr(foodIndex, 3) = regexColl(i).SubMatches(2)
foodArr(foodIndex, 4) = regexColl(i).SubMatches(3)
foodArr(foodIndex, 5) = regexColl(i).SubMatches(4)
Next i
End If
Set regexColl = Nothing
Set regex = Nothing
ActiveSheet.Cells(1, 1).Resize(UBound(foodArr, 1), UBound(foodArr, 2)).Value = foodArr
Erase foodArr
End Sub
Private Function OpenTxtFile(argPath As String) As String
Dim FSO As Scripting.FileSystemObject
Set FSO = New Scripting.FileSystemObject
Dim txtFile As TextStream
Set txtFile = FSO.OpenTextFile(argPath)
OpenTxtFile = txtFile.ReadAll
txtFile.Close
Set txtFile = Nothing
Set FSO = Nothing
End Function
Running ParseFoodJSON will parse the JSON given in OpenTxtFile (the first line) and print the result in your ActiveSheet which you will need to change to suit your purpose.
Using excel macro The first line is the json file name, and the second and subsequent columns are the values.
With the first column as the key to the json object,
only the values in the second column and only the values in the third column.
How do I generate json in batches in the same directory as the Excel respectively?
For example, column B is the value of column A as a key, the value of column B and b1.json. Column C uses the value of Column A as a key and the value of Column C and c1.json
For example, when the completed json has a description up to column C,
b1.json
[{
a2: b2,
a3: b3,
a4: b4,
}]
c1.json
[{
a2: c2,
a3: c3,
a4: c4,
}]
And want to be generated.
Here is VBA example showing how the files could be created. Import JSON.bas module from VBA JSON parser into the VBA project for JSON processing, and include a reference to "Microsoft Scripting Runtime" (take a look here how to import module and add reference).
Put the below code in a standard module:
Option Explicit
Sub test()
With ActiveSheet.Cells(1, 1).CurrentRegion
If .Cells.Count < 4 Then
MsgBox "No data"
Exit Sub
End If
Dim source
source = .Value
End With
Dim i
For i = 2 To UBound(source, 2)
Dim data
Set data = New Dictionary
Dim j
For j = 2 To UBound(source, 1)
data(source(j, 1)) = source(j, i)
Next
saveTextToFile _
JSON.Serialize(Array(data)), _
ThisWorkbook.path & "\" & source(1, i) & ".json", _
"UTF-8"
Next
MsgBox "Completed"
End Sub
Sub saveTextToFile(content, filePath, charset)
With CreateObject("ADODB.Stream")
.Type = 2 ' adTypeText
.Open
.charset = charset
.WriteText content
.Position = 0
.Type = 1 ' TypeBinary
.SaveToFile filePath, 2
.Close
End With
End Sub
The source data I tested code with:
The output is as follows:
file1.json
[
{
"prop1": "Alice",
"prop2": "Bob",
"prop3": "Charlie",
"prop4": "Eve",
"prop5": "Dan"
}
]
file2.json
[
{
"prop1": "Tomatoes",
"prop2": "Bananas",
"prop3": "Watermelons",
"prop4": "Apples",
"prop5": "Grapefruit"
}
]
file3.json
[
{
"prop1": "Russia",
"prop2": "Canada",
"prop3": "USA",
"prop4": "China",
"prop5": "Brazil"
}
]
BTW, the similar approach applied in other answers.
This is the exact problem I'm having but I can't seem to import the JSON.bas file. It throws an error saying the file is too complex.
I am trying to get "image_id" from the below json in different columns of a row.
[
{
"spin": "HM4C6L",
"attributes": {
"product name": "Everest Kutilal Coarse Ground Red Chilli Powder ",
},
"bar_code": {
"valid": true,
"id": "89017817",
"type": "UPC"
},
"spin_state": "LIVE",
"meta": {
"updated-by": "undefined"
},
"version": null,
"images": [
{
"image_id": "dvuewrnauxdroqcapjiu",
"image_name": "masala and spice_HM4A7I2C6L_MN.JPG",
"shot_type": "MN"
},
{
"image_id": "tcku7lwarkv8ch0ao9cu",
"image_name": "masala and spice_HM4A7I2C6L_AL1.JPG",
"shot_type": "AL1"
},
{
"image_id": "b2znlmm59plprrkmkujs",
"image_name": "masala and spice_HM4A7I2C6L_AL2.jpg",
"shot_type": "AL2"
}
]
}
]
I tried Cannot iterate when parsing HTML table using JSON-VBA and Loop through the JSON object keys in excel vba.
Sub getimage()
Dim current As Workbook
Dim sht As Worksheet
Dim a, b, strUrl As String
Dim count As Variant
Set current = ActiveWorkbook
For Each sht In current.Worksheets
On Error Resume Next
'Application.ScreenUpdating = False
Set HTTPReq = CreateObject("WinHttp.WinHttpRequest.5.1")
count = Range("A1", Range("A1").End(xlDown)).Rows.count
For i = 2 To count
a = CStr(Range("A" & i).Value)
HTTPReq.Open "GET", "link" & a, False
HTTPReq.send
'Debug.Print HTTPReq.ResponseText
Dim Json, item As Object
Set Json = JsonConverter.ParseJson(HTTPReq.ResponseText)
For Each item In Json
Debug.Print item("images")
sht.Cells(i, B) = item("image_id")("1")
sht.Cells(i, B) = item("image_id")("2")
next Item
Next i
'Application.ScreenUpdating = True
End If
Next sht
End Sub
I need "dvuewrnauxdroqcapjiu" in cell B2, tcku7lwarkv8ch0ao9cu in cell C2, and "b2znlmm59plprrkmkujs" in cell C2, but my code is giving no output, no error.
A number of things.
Your json is malformed. There is an extra "," here:
"Everest Kutilal Coarse Ground Red Chilli Powder ",
which means jsonconverter will throw an error. The "," at the end would be to separate the current key-value pair from the next. There isn't a following pair so it should be removed.
Your path for accessing is wrong.
Here I am reading the corrected json from cell A1
Option Explicit
Public Sub test()
Dim json As Object, i As Long, item As Object, c As Long
i = 2: c = 2
Set json = JsonConverter.ParseJson([A1])(1)("images")
For Each item In json
ActiveSheet.Cells(i, c) = item("image_id")
c = c + 1
Next
End Sub
Cells(2,B) will expect B to be a variable as string literals are wrapped in "" i.e. "B". Also, you need a counter variable which is incremented or you will keep writing to the same cell.
Thank you to #QHarr for working on this with me!
My goal is to grab the values for each of the nested categories from "orders"
my json:
{
"total": 14,
"_links": {
"next": {
"href": "/api/my/orders/selling/all?page=2&per_page=1"
}
},
"orders": [
{
"amount_product": {
"amount": "0.01",
"currency": "USD",
"symbol": "$"
},
"amount_product_subtotal": {
"amount": "0.01",
"currency": "USD",
"symbol": "$"
},
"shipping": {
"amount": "0.00",
"currency": "USD",
"symbol": "$"
},
"amount_tax": {
"amount": "0.00",
"currency": "USD",
"symbol": "$"
},
"total": {
"amount": "0.01",
"currency": "USD",
"symbol": "$"
},
"buyer_name": "Some Buyer",
"created_at": "2015-02-03T04:38:03-06:00",
"order_number": "434114",
"needs_feedback_for_buyer": false,
"needs_feedback_for_seller": false,
"order_type": "instant",
"paid_at": "2015-02-03T04:38:04-06:00",
"quantity": 1,
"shipping_address": {
"name": "Some Buyer",
"street_address": "1234 Main St",
"extended_address": "",
"locality": "Chicagoj",
"region": "IL",
"postal_code": "60076",
"country_code": "US",
"phone": "1231231234"
},
"local_pickup": false,
"shop_name": "Some Seller",
"status": "refunded",
"title": "DOD Stereo Chorus Extreme X GFX64",
"updated_at": "2015-03-06T11:59:27-06:00",
"payment_method": "direct_checkout",
"_links": {
"photo": {
"href": "https://reverb-res.cloudinary.com/image/upload/a_exif,c_thumb,f_auto,fl_progressive,g_south,h_192,w_192/v1386717988/h1zpe0sii9my0xm55htd.jpg"
},
"feedback_for_buyer": {
"href": "/api/orders/434114/feedback/buyer"
},
"feedback_for_seller": {
"href": "/api/orders/434114/feedback/seller"
},
"listing": {
"href": "/api/listings/47096"
},
"start_conversation": {
"href": "/api/my/conversations?listing_id=47096&recipient_id=302456"
},
"self": {
"href": "/api/my/orders/selling/434114"
},
"mark_picked_up": {
"href": "/api/my/orders/selling/434114/mark_picked_up"
},
"ship": {
"href": "/api/my/orders/selling/434114/ship"
},
"contact_buyer": {
"web": {
"href": "https://reverb.com/my/messages/new?item=47096-dod-stereo-chorus-extreme-x-gfx64&to=302456-yan-p-5"
}
}
},
"photos": [
{
"_links": {
"large_crop": {
"href": "https://reverb-res.cloudinary.com/image/upload/a_exif,c_thumb,f_auto,fl_progressive,g_south,h_640,q_85,w_640/v1386717988/h1zpe0sii9my0xm55htd.jpg"
},
"small_crop": {
"href": "https://reverb-res.cloudinary.com/image/upload/a_exif,c_thumb,f_auto,fl_progressive,g_south,h_296,q_85,w_296/v1386717988/h1zpe0sii9my0xm55htd.jpg"
},
"full": {
"href": "https://reverb-res.cloudinary.com/image/upload/a_exif,c_limit,f_auto,fl_progressive,h_1136,q_75,w_640/v1386717988/h1zpe0sii9my0xm55htd.jpg"
},
"thumbnail": {
"href": "https://reverb-res.cloudinary.com/image/upload/a_exif,c_thumb,f_auto,fl_progressive,g_south,h_192,w_192/v1386717988/h1zpe0sii9my0xm55htd.jpg"
}
}
}
],
"sku": "rev-47096",
"selling_fee": {
"amount": "0.00",
"currency": "USD",
"symbol": "$"
},
"direct_checkout_payout": {
"amount": "-0.24",
"currency": "USD",
"symbol": "$"
}
}
]
}
If I have one good example of how to work with the nested data I am sure I can get this to work. This is my current code, it doesn't work... this is the error- "the object doesn't support this property or method" on this line: For Each Amount_Product In Orders("amount_product"). What I am expecting is to be able to extract the value of each of the amount_product "items" and push them into variables so that I can then push them into a table.
Dim Json As Object
Dim FSO As New FileSystemObject
Dim JsonTS As TextStream
Dim JsonText As String
Dim Parsed As Dictionary
'set up variables to receive the values
Dim sAmount As String
Dim sCurrency As String
Dim sSymbol As String
'Read .json file
Set JsonTS = FSO.OpenTextFile("somefilepath.txt", ForReading)
JsonText = JsonTS.ReadAll
JsonTS.Close
'came from https://github.com/VBA-tools/VBA-JSON
Set Parsed = JsonConverter.ParseJson(JsonText)
Dim Values As Variant
Dim Orders As Dictionary
Dim NestedValue As Dictionary
Dim i As Long
i = 0
For Each Orders In Parsed("orders")
For Each NestedValue In Orders("amount_product")
sAmount = (Values(i, 0) = NestedValue("amount"))
sCurrency = (Values(i, 1) = NestedValue("currency"))
sSymbol = (Values(i, 2) = NestedValue("symbol"))
i = i + 1
Next NestedValue
Next Orders
I also tried this- based on some examples of code I have found, this doesn't work either:
For Each NestedValue In Parsed("orders")(1)("amount_product")
sAmount = (Values(i, 0) = NestedValue("amount"))
sCurrency = (Values(i, 1) = NestedValue("currency"))
sSymbol = (Values(i, 2) = NestedValue("symbol"))
i = i + 1
Next NestedValue
I tried using this VBA Parse Nested JSON example by #TimWilliams but was not successful in tweaking it to work with my Json. Same error, "object doesn't support this property or method" on the line "For Each NestedValue In Parsed("orders")(1)("amount_product")"
Ok solved (Oops....I think!). So, here are two versions dealing with the same JSON.
Version 1: A simple example showing you how to get the Amount_Product values you were after. Not the easiest to read syntax, but I have given the lengthy descriptions/syntax in version 2.
Version 2: Extracting all the values from the JSON.
Additional set-up requirements:
1) Reference required to MS Scripting Runtime in VBE > Tools > References
2) JSON Converter module by Tim Hall
Process:
I used TypeName(object) , at each stage, to understand which objects were being returned from the JSON. I have left some of these in (commented out as Debug.Print statements) so you have an idea what is going on at each stage.
Observations:
1) JsonConverter.ParseJson(JsonText) returns a dictionary to Parsed.
2) Parsed("orders") returns a collection which holds a single dictionary i.e. initialCollection(1)
3) That dictionary holds a variety of objects which is perhaps what is rather confusing.
If you run the following, to look at the objects in the dictionary:
Debug.Print TypeName(initialDict(key))
You discover what a busy little dictionary it is. It hosts the following:
Boolean * 3
Collection * 1
Dictionary * 9
Double * 1
String * 11
And so of course you keep delving into deeper levels of the nesting via these structures. The different handling, according to datatype, I have done via Select Case. I have tried to keep the terminology fairly straight forward.
How to use an Online JSON parser to examine structure:
So there are a number of online JSON parsers out there.
You pop your code in the left window (of the example I have given) and the right window shows the evaluation:
If you look at the initial red "[" ; this is the collection object you are getting with Parsed("orders").
Then you can see the first "{" before the "amount_product" which is your first dictionary within the collection.
And within that, associated with "amount_product" id, is the next dictionary where you see the next "{"
So you know you have to get the collection and then potentially iterate over two dictionaries to get the first set of values you were interested in.
I used a shortcut with Parsed("orders")(1)("amount_product").Keys ,in the first code example, to get to this inner dictionary to iterate over.
Results:
Code:
Version 1 (Simple):
Option Explicit
Public Sub test1()
Dim Json As Object
Dim FSO As New FileSystemObject
Dim JsonTS As TextStream
Dim JsonText As String
Set JsonTS = FSO.OpenTextFile("C:\Users\User\Desktop\Document.txt", ForReading)
JsonText = JsonTS.ReadAll
JsonTS.Close
Dim Parsed As Dictionary 'or As Object if not including reference to scripting runtime reference in library
Set Parsed = JsonConverter.ParseJson(JsonText)
Dim key As Variant
Dim sAmount As String 'Assume you will keep these as strings?
Dim sCurrency As String
Dim sSymbol As String
For Each key In Parsed("orders")(1)("amount_product").Keys
Dim currentString As String
currentString = Parsed("orders")(1)("amount_product")(key)
Select Case key
Case "amount"
sAmount = currentString
Case "currency"
sCurrency = currentString
Case "symbol"
sSymbol = currentString
End Select
Debug.Print key & ": " & currentString
Next key
End Sub
Version 2: Grab everything. More descriptive.
Option Explicit
Sub test2()
Dim Json As Object
Dim FSO As New FileSystemObject
Dim JsonTS As TextStream
Dim JsonText As String
Set JsonTS = FSO.OpenTextFile("C:\Users\User\Desktop\Document.txt", ForReading) 'change as appropriate
JsonText = JsonTS.ReadAll
JsonTS.Close
Dim Parsed As Dictionary
Set Parsed = JsonConverter.ParseJson(JsonText)
Dim initialCollection As Collection
Set initialCollection = Parsed("orders")
' Debug.Print initialCollection.Count ' 1 item which is a dictionary
Dim initialDict As Dictionary
Set initialDict = initialCollection(1)
Dim key As Variant
Dim dataStructure As String
For Each key In initialDict.Keys
dataStructure = TypeName(initialDict(key))
Select Case dataStructure
Case "Dictionary"
Dim Key1 As Variant
For Each Key1 In initialDict(key).Keys
Select Case TypeName(initialDict(key)(Key1))
Case "String"
Debug.Print key & " " & Key1 & " " & initialDict(key)(Key1) 'amount/currency/symbol
Case "Dictionary"
Dim Key2 As Variant
For Each Key2 In initialDict(key)(Key1).Keys
'Debug.Print TypeName(initialDict(key)(Key1)(Key2)) 'strings and one dict
Select Case TypeName(initialDict(key)(Key1)(Key2))
Case "String"
Debug.Print key & " " & Key1 & " " & Key2 & " " & initialDict(key)(Key1)(Key2)
Case "Dictionary"
Dim Key3 As Variant
For Each Key3 In initialDict(key)(Key1)(Key2).Keys
'Debug.Print TypeName(initialDict(key)(Key1)(Key2)(Key3)) 'string only
Debug.Print initialDict(key)(Key1)(Key2)(Key3)
Next Key3
End Select
Next Key2
Case Else
MsgBox "Oops I missed this one"
End Select
Next Key1
Case "String", "Boolean", "Double"
Debug.Print key & " : " & initialDict(key)
Case "Collection"
'Debug.Print TypeName(initialDict(key)(1)) 'returns 1 Dict
Dim Key4 As Variant
For Each Key4 In initialDict(key)(1).Keys 'Debug.Print TypeName(initialDict(key)(1)(Key4)) 'returns a dictionary
Dim Key5 As Variant
For Each Key5 In initialDict(key)(1)(Key4).Keys ' Debug.Print TypeName(initialDict(key)(1)(Key4)(Key5)) returns 4 dictionaries
Dim Key6 As Variant
For Each Key6 In initialDict(key)(1)(Key4)(Key5).Keys 'returns string
Debug.Print key & " " & Key4 & " " & Key5 & " " & Key6 & " " & initialDict(key)(1)(Key4)(Key5)(Key6)
Next Key6
Next Key5
Next Key4
Case Else
MsgBox "Oops I missed this one!"
End Select
Next key
End Sub
Final observation:
To be consistent, and to aid demonstrating what is going on, I have added all the .Keys, but it is unnecessary, when iterating in a For Each Loop over a Dictionary, to put .Keys, as shown in test below and in the embedded gif:
Option Explicit
Private Sub test()
Dim testDict As Dictionary
Set testDict = New Dictionary
testDict.Add "A", 1
testDict.Add "B", 2
Dim key As Variant
For Each key In testDict
Debug.Print key & ":" & testDict(key)
Next key
End Sub
So for example:
For Each key In initialDict.Keys => For Each key In initialDict
I combined V1 and V2 above to produce the results, which was to capture values and save them into variables. This is my edited code: (I am still working on creating all of the cases and variables)
Dim Json As Object
Dim FSO As New FileSystemObject
Dim JsonTS As TextStream
Dim JsonText As String
Set JsonTS = FSO.OpenTextFile("C:\some.txt", ForReading) 'change as appropriate
JsonText = JsonTS.ReadAll
JsonTS.Close
Dim Parsed As Dictionary
Set Parsed = JsonConverter.ParseJson(JsonText)
Dim initialCollection As Collection
Set initialCollection = Parsed("orders")
Debug.Print initialCollection.Count ' 1 item which is a dictionary
Dim initialDict As Dictionary
Set initialDict = initialCollection(1)
Dim Key As Variant
Dim dataStructure As String
For Each Key In initialDict.Keys
dataStructure = TypeName(initialDict(Key))
Select Case dataStructure
Case "Dictionary"
Dim Key1 As Variant
For Each Key1 In initialDict(Key).Keys
Select Case TypeName(initialDict(Key)(Key1))
Case "String"
'Debug.Print Key & " " & Key1 & " " & initialDict(Key)(Key1) 'amount/currency/symbol
'because the Key1 (amount) is the same for each Key ("Amount_product", "Amount_product_subtotal", and so on; (see Json above) I needed to concatenate them to extract unique values
Select Case Key & "_" & Key1
'first set of values "Amount_Product"
Case "Amount_product_amount"
dAmount_product_amount = initialDict(Key)(Key1)
Case "Amount_product_currency"
sAmount_product_currency = initialDict(Key)(Key1)
Case "Amount_product_symbol"
sAmount_product_symbol = initialDict(Key)(Key1)
'second set of values "Amount_Product_Subtotal"
Case "Amount_product_subtotal_amount"
dAmount_product_subtotal_amount = initialDict(Key)(Key1)
Case "Amount_product_subtotal_currency"
sAmount_product_subtotal_currency = initialDict(Key)(Key1)
Case "Amount_product_subtotal_symbol"
sAmount_product_subtotal_symbol = initialDict(Key)(Key1)
' third set of values, and so on
End Select
'Debug.Print Key & ": " & Key1
Case "Dictionary"
Dim Key2 As Variant
For Each Key2 In initialDict(Key)(Key1).Keys
'Debug.Print TypeName(initialDict(key)(Key1)(Key2)) 'strings and one dict
Select Case TypeName(initialDict(Key)(Key1)(Key2))
Case "String"
Debug.Print Key & " " & Key1 & " " & Key2 & " " & initialDict(Key)(Key1)(Key2)
Case "Dictionary"
Dim Key3 As Variant
For Each Key3 In initialDict(Key)(Key1)(Key2).Keys
'Debug.Print TypeName(initialDict(key)(Key1)(Key2)(Key3)) 'string only
Debug.Print initialDict(Key)(Key1)(Key2)(Key3)
Next Key3
End Select
Next Key2
Case Else
MsgBox "Oops I missed this one"
End Select
Next Key1
Case "String", "Boolean", "Double"
Debug.Print Key & " : " & initialDict(Key)
Case "Collection"
'Debug.Print TypeName(initialDict(key)(1)) 'returns 1 Dict
Dim Key4 As Variant
For Each Key4 In initialDict(Key)(1).Keys 'Debug.Print TypeName(initialDict(key)(1)(Key4)) 'returns a dictionary
Dim Key5 As Variant
For Each Key5 In initialDict(Key)(1)(Key4).Keys ' Debug.Print TypeName(initialDict(key)(1)(Key4)(Key5)) returns 4 dictionaries
Dim Key6 As Variant
For Each Key6 In initialDict(Key)(1)(Key4)(Key5).Keys 'returns string
Debug.Print Key & " " & Key4 & " " & Key5 & " " & Key6 & " " & initialDict(Key)(1)(Key4)(Key5)(Key6)
Next Key6
Next Key5
Next Key4
Case Else
MsgBox "Oops I missed this one!"
End Select
Next Key
End Sub
I'm getting data from a AQI API from China, I'm putting some of the data into a SQL server database and that works just dandy. I also decided to add everything returned from the API into a JSON file so I can access it later.
Whenever I try to append the string returned by the API into the file I get a "Invalid procedure call or argument" error
This is what I have done so far:
Public Sub AddToJson(Jsonline As String)
Dim strfile As String
Dim fso As New FileSystemObject
Dim fsoStream As TextStream
Dim iexist As String
Dim stradd As String
strfile = "c:\JSON_AQI.json"
stradd = Replace(Jsonline, Chr(34), Chr(34) & Chr(34) & Chr(34) & Chr(34))
Debug.Print stradd
iexist = Dir(strfile)
'check if the file exists
If iexist = "" Then
'if it exists, open it and add the line
Set fsoStream = fso.CreateTextFile(strfile)
Else
'if it doesn't exist, create it and add the line
Set fsoStream = fso.OpenTextFile(strfile, ForAppending)
End If
fsoStream.WriteLine stradd
fsoStream.Close
Set fsoStream = Nothing
Set fso = Nothing
End Sub
This is what I pass as the Jsonline parameter:
{"status":"ok","data":{"aqi":164,"idx":7130,"attributions":[{"name":"Hunan Environmental Protection Agency (????????)"},{"name":"China National Urban air quality real-time publishing platform (??????????????)"}],"city":{"geo":[33.8561,115.7831],"name":"sanguó lanshèng gong, Bozhou"},"dominentpol":"pm25","iaqi":{"co":{"v":14.8},"no2":{"v":24.7},"o3":{"v":45.9},"pm10":{"v":97},"pm25":{"v":164},"so2":{"v":5.1}},"time":{"s":"2017-04-06 04:00:00","tz":"+08:00","v":1491451200}}}
as you can see I tried adding extra double quotes to the string to no avail, is there anything else that I'm missing?
Actually the received JSON contains Chinese characters instead of ? you posted and should look like:
{
"status": "ok",
"data": {
"aqi": 164,
"idx": 7130,
"attributions": [
{
"name": "Hunan Environmental Protection Agency (湖南省环境保护厅)"
},
{
"name": "China National Urban air quality real-time publishing platform (全国城市空气质量实时发布平台)"
}
],
"city": {
"geo": [
33.8561,
115.7831
],
"name": "sanguó lanshèng gong, Bozhou"
},
"dominentpol": "pm25",
"iaqi": {
"co": {
"v": 14.8
},
"no2": {
"v": 24.7
},
"o3": {
"v": 45.9
},
"pm10": {
"v": 97
},
"pm25": {
"v": 164
},
"so2": {
"v": 5.1
}
},
"time": {
"s": "2017-04-06 04:00:00",
"tz": "+08:00",
"v": 1491451200
}
}
}
Therefore you have to set encoding of the snippet being appended as Unicode explicitly. I suggest to use the below simple functions to read, write and append text files via Scripting.FileSystemObject:
Function ReadTextFile(sPath As String, lFormat As Long) As String
' lFormat -2 - System default, -1 - Unicode, 0 - ASCII
With CreateObject("Scripting.FileSystemObject").OpenTextFile(sPath, 1, False, lFormat)
ReadTextFile = ""
If Not .AtEndOfStream Then ReadTextFile = .ReadAll
.Close
End With
End Function
Sub WriteTextFile(sContent As String, sPath As String, lFormat As Long)
With CreateObject("Scripting.FileSystemObject").OpenTextFile(sPath, 2, True, lFormat)
.Write sContent
.Close
End With
End Sub
Sub AppendTextFile(sContent As String, sPath As String, lFormat As Long)
With CreateObject("Scripting.FileSystemObject").OpenTextFile(sPath, 8, True, lFormat)
.Write sContent
.Close
End With
End Sub
So you can append the string by the calling:
AppendTextFile Jsonline & vbCrLf, "C:\JSON_AQI.json", -1