Parse JSON objects and collection using VBA - arrays

I have a JSON file which contains:
array("components") of Objects
some of objects may have sub array("components") some don't.
I need to extract the labels, keys of that array also the array("values") with all the labels, values.
HOWEVER following VBA code only work with first level of "components", do not dig into second or third levels. let me know if I am doing it right?
I have been using JsonConverter to parse JSON file and then using following code:
Dim jSon As Variant
Set jSon = JsonConverter.ParseJson(jSonText)
Dim components As Collection
Set components = jSon("components")
Set Dict = New Scripting.Dictionary
Dim component As Variant
For Each component In components
Dim Label, Key As String 'not used
Dict.Add component("label"), component("key")
On Error Resume Next
Dim Values As Collection
Set Values = component("components")
Dim Data As Scripting.Dictionary
Set Data = component("data")
On Error GoTo 0
Dim value As Variant
If Not Values Is Nothing Then
For Each value In Values
Dict.Add value("label"), value("value")
Next value
ElseIf Not Data Is Nothing Then
Set Values = Data("values")
For Each value In Values
Dict.Add value("label"), value("value")
Next value
Else
'Debug.Print " No values"
End If
Set Values = Nothing
Set Data = Nothing
Next component
OLD JSON FILE - above code is working fine on this
{
"display": "form",
"settings": {
"pdf": {
"id": "1ec0f8ee-6685-5d98-a847-26f67b67d6f0",
"src": "https://files8-a847-26f67b67d6f08-a847-26f67b67d6f0"
}
},
"components": [
{
"label": "Family Name",
"tableView": true,
"key": "familyName",
"type": "textfield",
"input": true
},
{
"label": "Amount of Money",
"mask": false,
"tableView": false,
"delimiter": false,
"requireDecimal": false,
"inputFormat": "plain",
"truncateMultipleSpaces": false,
"key": "amountOfMoney",
"type": "number",
"input": true
},
{
"label": "I hereby confirm",
"tableView": false,
"key": "iHerebyConfirm",
"type": "checkbox",
"input": true,
"defaultValue": false
},
{
"label": "Which Cities do you like",
"optionsLabelPosition": "right",
"tableView": false,
"values": [
{
"label": "New York",
"value": "newNew YorkYork",
"shortcut": ""
},
{
"label": "Munich",
"value": "Munich",
"shortcut": ""
},
{
"label": "Paris",
"value": "Paris",
"shortcut": ""
},
{
"label": "Hongkong",
"value": "Hongkong",
"shortcut": ""
},
{
"label": "Mumbai",
"value": "Mumbai",
"shortcut": ""
}
],
"key": "whichCitiesDoYouLike",
"type": "selectboxes",
"input": true,
"inputType": "checkbox"
},
{
"label": "Favorite color",
"widget": "choicesjs",
"tableView": true,
"data": {
"values": [
{
"label": "black",
"value": "black"
},
{
"label": "white",
"value": "white"
},
{
"label": "blue",
"value": "blue"
},
{
"label": "green",
"value": "green"
}
]
},
"key": "favoriteColor",
"type": "select",
"input": true
},
{
"type": "button",
"label": "Submit",
"key": "submit",
"disableOnInvalid": true,
"input": true,
"tableView": false
}
]
}
To understand it I used http://jsoneditoronline.org/ try to convey in following picture

Take note that I have swapped the dictionary entry using key as the dictionary key and label as the value as label is not unique (as far as the sample JSON shows) and will cause an error (or overwrite previous entry, depending on implementation).
Your usage of On Error Resume Next should be avoided (this applies to any scenario, unless you are using it on purpose which is rarely needed) as you are basically hiding all possible errors which can cause your code to produce unintended result. You can use Exists method in If..Else..End If statement to check if the dictionary key exist first and only perform the task if it do exist.
EDIT - Code updated to handle both old and new JSON format
Private Sub Test()
'==== Change this part according to your implementation..."
Dim jsontxt As String
jsontxt = OpenTxtFile("D:/TestJSON2.txt")
'====
Dim jSon As Scripting.Dictionary
Set jSon = JsonConverter.ParseJson(jsontxt)
'Check if first level of components exist and get the collection of components if true
If jSon.Exists("components") Then
Dim components As Collection
Set components = jSon("components")
Dim Dict As Scripting.Dictionary
Set Dict = New Scripting.Dictionary
Dim comFirst As Variant
Dim comSecond As Variant
Dim comThird As Variant
Dim columnsDict As Variant
Dim valDict As Variant
For Each comFirst In components
'extract key-label from first level component
If Not Dict.Exists(comFirst("label")) Then Dict.Add comFirst("label"), comFirst("key")
'++++ New JSON Format ++++
'==== Check if second level of "components" key exist and extract label-key if true
If comFirst.Exists("components") Then
For Each comSecond In comFirst("components")
If Not Dict.Exists(comSecond("label")) Then Dict.Add comSecond("label"), comSecond("key")
'=== Check if "columns" key exist and extract the key-label if true
If comSecond.Exists("columns") Then
For Each columnsDict In comSecond("columns")
'==== Check if third level of "components" key exist and extract key-label if true
If columnsDict.Exists("components") Then
For Each comThird In columnsDict("components")
If Not Dict.Exists(comThird("label")) Then Dict.Add comThird("label"), comThird("key")
'==== Check if "values" key exist and extract label-value if true
If comThird.Exists("values") Then
For Each valDict In comThird("values")
If Not Dict.Exists(valDict("label")) Then Dict.Add valDict("label"), valDict("value")
Next valDict
End If
'====
Next comThird
End If
'====
Next columnsDict
End If
'====
'==== Check if "values" key exist and extract the label-value if true
If comSecond.Exists("values") Then
For Each valDict In comSecond("values")
If Not Dict.Exists(valDict("label")) Then Dict.Add valDict("label"), valDict("value")
Next valDict
End If
'====
Next comSecond
End If
'++++
'++++ Old JSON format ++++
'==== Check if "data" key exist and extract the label-value if true
If comFirst.Exists("data") Then
If comFirst("data").Exists("values") Then
For Each valDict In comFirst("data")("values")
If Not Dict.Exists(valDict("label")) Then Dict.Add valDict("label"), valDict("value")
Next valDict
End If
End If
'====
'==== Check if "values" key exist and extract the label-value if true
If comFirst.Exists("values") Then
For Each valDict In comFirst("values")
If Not Dict.Exists(valDict("label")) Then Dict.Add valDict("label"), valDict("value")
Next valDict
End If
'====
'++++
Next comFirst
End If
End Sub

Try this:
https://github.com/VBA-tools/VBA-JSON
You need to import the file "JsonConverter.bas" in your project and then follow the examples in the README.md file

Related

RUBY parse nested JSON Object

I have a ruby script that works pretty well. I'm parsing JSON from an API and passing it into and array.
Most of the top elements parse fine. But I have a nested object that looks like this after its a hash...
I did and inspect on it and outputted the current data object I'm looking at.
orf1: ["displayValue", "DNAORF999-N9, DNAORF888-N9, DNAORF777-N9, DNAORF444-N9"]
orf1_inspect: ["displayValue", "DNAORF999-N9, DNAORF888-N9, DNAORF777-N9, DNAORF444-N9"]
orf1: ["isMulti", true]
orf1_inspect: ["isMulti", true]
orf1: ["textValue", "DNAORF999-N9, DNAORF888-N9, DNAORF777-N9, DNAORF444-N9"]
orf1_inspect: ["textValue", "DNAORF999-N9, DNAORF888-N9, DNAORF777-N9, DNAORF444-N9"]
orf1: ["type", "entity_link"]
orf1_inspect: ["type", "entity_link"]
orf1: ["value", ["seq_dfdfdfdfd", "seq_fdfdfd", "seq_fdfdfdd", "seq_jfdfdfd"]]
Here is the section of code that returns the above..Let me know if you need more info?
if row["fields"]["ORF"].nil? || row["fields"]["ORF"].empty?
orf = nil
else
row["fields"]["ORF"].each do |orf1|
puts 'orf1: ' + orf1.to_s
orfinspect = orf1.inspect
puts 'orf1_inspect: ' + orfinspect
end
end
I cant seem to parse oput the individual values.
I need to get the values/data from these fields... displayValue, isMulti, textValue, type, and value
Ive tried all kinds of approaches.. Some give conversion errors. I can use orf1.first and that works... but its only part of it...
Even this will get me the header for textvalue
orf = orf1[0]["textValue"]
puts 'orf: ' + orf.to_s
here is the inspect on row["fields"]["ORF"].inspect if it helps..
{
"displayValue" => "DNAORF888-N9, DNAORF999-N9, DNAORF444-N9, DNAORF321-N9, DNAORF111-N9, DNAORF777-N9, DNAORF222-N9, DNAORF425-N9, DNAORF122-N9",
"isMulti" => true,
"textValue" => "DNAORF888-N9, DNAORF999-N9, DNAORF444-N9, DNAORF321-N9, DNAORF111-N9, DNAORF777-N9, DNAORF222-N9, DNAORF425-N9, DNAORF122-N9", "type"=>"entity_link",
"value" => ["seq_jddddaA2", "seq_sfgsfff", "seq_osfsffs", "seq_fsdfsd", "seq_fsdfsd", "seq_fsfsfsfs", "seq_sfsfss", "seq_sfsfsf", "seq_sfsfs"]
}
This seems to work. Is this the best approach?
row["fields"]["ORF"].each do |key,value|
if key == 'displayValue'
unless value.nil?
orf_displayValue=value
end
end
if key == 'isMulti'
unless value.nil?
orf_isMulti=value
end
end
if key == 'textValue'
unless value.nil?
orf_textValue=value
end
end
if key == 'type'
unless value.nil?
orf_type=value
end
end
if key == 'value'
unless value.nil?
orf_value=value
end
end
end
end
But I would need to do this for each field. I feel like there is a better way..
As the error says:
can't convert Symbol into Integer
textValue is of type Symbol and when you are looping over data you end with first key and value which is displayValue and DNAORF004-N9 and inside do end block you are accessing DNAORF004-N9 index with textValue which is Symbol which is not possible it should be integer as the error states.
data = {"displayValue"=>"DNAORF004-N9", "isMulti"=>true, "textValue"=>"DNAORF001-N9", "type"=>"entity_link", "value"=>["seq_fdfdf", "seq_9fdfdfdfd"]}
datasequences = [ :displayValue, :textValue ]
datasequences.each do |textValue|
puts "textValue is #{textValue.inspect}"
data.each do |key, value|
puts "\t#{value[textValue]} at #{key}"
end
end
To resolve the issue you can change the code as below:
data = {"displayValue"=>"DNAORF004-N9", "isMulti"=>true, "textValue"=>"DNAORF001-N9", "type"=>"entity_link", "value"=>["seq_fdfdf", "seq_9fdfdfdfd"]}
datasequences = [ :displayValue, :textValue ]
# changing all keys from string to symbol
data = data.transform_keys(&:to_sym)
datasequences.each do |textValue|
puts "textValue is #{textValue.inspect}"
puts "Value: #{data[textValue]}"
end
value = {
"dnaSequences": [
{
"aliases": [],
"annotations": [],
"apiURL": "https://url",
"archiveRecord": nil,
"authors": [
{
"handle": "dsdsd",
"id": "ent_dsdsd",
"name": "dsdsd"
}
],
"bases": "",
"createdAt": "2020-07-14T21:39:26.991794+00:00",
"creator": {
"handle": "dsds",
"id": "ent_dsdsd",
"name": "dsdd Fdsdsdso"
},
"customFields": {},
"dnaAlignmentIds": [],
"entityRegistryId": "MOUSE006",
"fields": {
"Identical mouses": {
"displayValue": nil,
"isMulti": false,
"textValue": nil,
"type": "part_link",
"value": nil
},
"Library Constructed By": {
"displayValue": "dsdsd",
"isMulti": false,
"textValue": "dsdsd",
"type": "dropdown",
"value": "sfso_dsdsd"
},
"Library Construction Date": {
"displayValue": "2020-06-01",
"isMulti": false,
"textValue": "2020-06-01",
"type": "date",
"value": "2020-06-01"
},
"Library Description": {
"displayValue": "dsdsdds",
"isMulti": false,
"textValue": "dsdsdsd",
"type": "text",
"value": "dsdsdsdsd"
},
"Library Sample Source": {
"displayValue": "dsdsds",
"isMulti": false,
"textValue": "dsdsdsds",
"type": "dropdown",
"value": "sfso_dsdsdsd"
},
"ORF": {
"displayValue": "DNAORF004-N9, DNAORF005-N9, DNAORF008-N9, DNAORF001-N9",
"isMulti": true,
"textValue": "DNAORF004-N9, DNAORF005-N9, DNAORF008-N9, DNAORF001-N9",
"type": "entity_link",
"value": [
"seq_aaaaaa",
"seq_bbbbbb",
"seq_ccccc",
"seq_ddddd"
]
},
"Re-Run ORF?": {
"displayValue": nil,
"isMulti": false,
"textValue": nil,
"type": "dropdown",
"value": nil
},
"Sampling GPS Coordinates": {
"displayValue": nil,
"isMulti": false,
"textValue": nil,
"type": "text",
"value": nil
},
"Sequencing Approach": {
"displayValue": "Single Sequence",
"isMulti": false,
"textValue": "Single Sequence",
"type": "dropdown",
"value": "gfgf"
},
"Sequencing Method": {
"displayValue": "gfgf fgfgfg",
"isMulti": false,
"textValue": "gfgf gfgfg",
"type": "dropdown",
"value": "sfsogfgfg_irlx6NfZ"
}
},
"folderId": "gfgfg",
"id": "gfgfgf",
"isCircular": false,
"length": 25129,
"modifiedAt": "2022-04-05T17:06:25.491926+00:00",
"name": "COPE03-P19",
"primers": [],
"registrationOrigin": {
"originEntryId": nil,
"registeredAt": "2020-07-14T22:15:09.541243+00:00"
},
"registryId": "gfgfgfg",
"schema": {
"id": "ps_fdfdfd",
"name": "mouse"
},
"translations": [],
"url": "hyyps:///COPE/f//edit",
"webURL": "https://url"
}
]
}
datasequences = [ :displayValue, :isMulti, :textValue, :type, :value ]
result = value["dnaSequences".to_sym].map do |v|
row = {}
if v.key?(:fields) && v[:fields].key?(:ORF)
datasequences.map do |key|
row[key] = v[:fields][:ORF][key.to_sym]
end
end
row
end
puts result
Note: Tested with Ruby 3.0.0

How to get all items in multiple Arrays in a JSON file using VBA?

Basically I want to read some .JSONn files with very structured data (many arrays, items and values) and my goal is to put the items and values in an excel sheet. I have trouble getting stuck when I reach arrays data-type.
I can read the files and include some items and values using the Library VBA-JSON 2.3.1
Dim jsonObject As Object, i As Integer, FSO
Set FSO = CreateObject("Scripting.FileSystemObject")
Set JsonTS = FSO.OpenTextFile("D:\JSON\file.json", ForReading)
JsonText = JsonTS.ReadAll
JsonTS.Close
Set ws = Worksheets("Sheet1")
Set jsonObject = JsonConverter.ParseJson(JsonText)
i = 2
n = 1
For Each Item In jsonObject
ws.Cells(i, n) = jsonObject(Item)
i = i + 1: n = n + 1
Next
MsgBox ("Complete!")
Set jsonObject = Nothing
Here's my sructured JSON file:
{
"id": "2ca5da11-b311-43db-9661-afa3b833aad4",
"name": "_menuAposentacoes",
"auto": true,
"contexts": [],
"responses": [
{
"resetContexts": false,
"affectedContexts": [
{
"name": "aposentacoes_22-followup",
"parameters": {},
"lifespan": 2
}
],
"parameters": [
{
"id": "6e86b18e-77c1-4571-ad53-eba8db91d4b3",
"required": false,
"dataType": "#aposentacao",
"name": "aposentacao",
"value": "$aposentacao",
"promptMessages": [],
"noMatchPromptMessages": [],
"noInputPromptMessages": [],
"outputDialogContexts": [],
"isList": true
},
{
"id": "be28b756-32dd-40e7-99db-d7f91cc9ddb6",
"required": false,
"dataType": "#CGA",
"name": "CGA",
"value": "$CGA",
"promptMessages": [],
"noMatchPromptMessages": [],
"noInputPromptMessages": [],
"outputDialogContexts": [],
"isList": false
},
{
"id": "f52786f0-15cd-4fc4-983f-32b248ddcf3f",
"required": false,
"dataType": "#descontos",
"name": "descontos",
"value": "$descontos",
"promptMessages": [],
"noMatchPromptMessages": [],
"noInputPromptMessages": [],
"outputDialogContexts": [],
"isList": false
},
{
"id": "6e7f4c49-f35f-46fb-9db9-c24eb16f0b40",
"required": false,
"dataType": "#situacaoCGA",
"name": "situacaoCGA",
"value": "$situacaoCGA",
"promptMessages": [],
"noMatchPromptMessages": [],
"noInputPromptMessages": [],
"outputDialogContexts": [],
"isList": false
},
{
"id": "70328121-e748-4508-a287-7fc30a9cd9f6",
"required": false,
"dataType": "#penalizacao",
"name": "penalizacao",
"value": "$penalizacao",
"promptMessages": [],
"noMatchPromptMessages": [],
"noInputPromptMessages": [],
"outputDialogContexts": [],
"isList": false
}
],
"messages": [
{
"type": 0,
"lang": "pt",
"speech": "Some text."
},
{
"type": 4,
"lang": "pt",
"payload": {
"message": "Some text: ",
"ignoreTextResponse": false,
"platform": "kommunicate",
"metadata": {
"contentType": "300",
"templateId": "6",
"payload": [
{
"title": "Other text",
"message": "Other text"
},
{
"title": "Other text",
"message": "Other text"
},
{
"title": "Other text",
"message": "Other text"
},
{
"title": "Other text",
"message": "Other text"
}
]
}
}
},
{
"type": 4,
"lang": "pt",
"payload": {
"message": "Other text",
"ignoreTextResponse": false,
"platform": "kommunicate",
"metadata": {
"contentType": "300",
"templateId": "6",
"payload": [
{
"title": "Sim",
"message": "Sim"
},
{
"title": "Não",
"message": "Não"
}
]
}
}
}
],
"defaultResponsePlatforms": {},
"speech": []
}
],
"priority": 500000,
"webhookUsed": false,
"webhookForSlotFilling": false,
"fallbackIntent": false,
"events": []
}
Here's a useful routine that can help you determine how to parse the JSON data, based on information in this answer. The routine is recursive, so it will successively call itself to continue parsing the JSON input.
The current output is to the immediate window using Debug.Print, but you can modify these statements to put the results into worksheet cells according to your needs and format (which was not really specified in your question).
Notice that the level parameter is incremented by two with each JSON level. This is likely due to the format of the JSON source itself. For example, the top-level responses field has both a [ and a { to indicate internal structure. You can adjust the logic to deal with this however best suits your use case.
Option Explicit
Sub ImportJSON()
Dim fso As FileSystemObject
Set fso = CreateObject("Scripting.FileSystemObject")
Dim jsonFilename As String
Dim jsonFile As Object
Dim jsonText As String
jsonFilename = "D:\JSON\file.json"
Set jsonFile = fso.OpenTextFile(Filename:=jsonFilename, IOMode:=ForReading)
jsonText = jsonFile.ReadAll
jsonFile.Close
Dim json As Object
Set json = JsonConverter.ParseJson(jsonText)
OutputJSON "(top)", json, 1
End Sub
Sub OutputJSON(ByVal itemName As String, _
ByRef jsonItem As Variant, _
ByVal level As Long)
Dim item As Variant
Select Case TypeName(jsonItem)
Case "Dictionary"
For Each item In jsonItem
If IsObject(jsonItem(item)) Then
If jsonItem(item).Count = 0 Then
Debug.Print level & " " & itemName & "." & _
item & " is empty " & _
TypeName(jsonItem(item))
Else
OutputJSON itemName & "." & item, jsonItem(item), level + 1
End If
Else
Debug.Print level & " " & itemName & "." & _
item & " = " & jsonItem(item)
End If
Next item
Case "Collection"
Dim i As Long
i = 1
For Each item In jsonItem
If IsObject(item) Then
OutputJSON itemName & "[" & i & "]", item, level + 1
Else
Debug.Print level & ": " & itemName & "[" & i & "]", item
End If
i = i + 1
Next item
End Select
End Sub

Problem while parsing a specific JSON in VBA

im trying right now parsing mutliple JSONs in VBA in Excel. With Google and SO i managed to parse Multiple JSONs in a Format like this:
{
"name": "Starker Geschmeidiger Holz-Langbogen des Feuers",
"description": "",
"type": "Weapon",
"level": 44,
"rarity": "Masterwork",
"vendor_value": 120,
"default_skin": 3942,
"game_types": [
"Activity",
"Wvw",
"Dungeon",
"Pve"
],
"flags": [
"SoulBindOnUse"
],
"restrictions": [],
"id": 28445,
"chat_link": "[&AgEdbwAA]",
"icon": "https://render.guildwars2.com/file/C6110F52DF5AFE0F00A56F9E143E9732176DDDE9/65015.png",
"details": {
"type": "LongBow",
"damage_type": "Physical",
"min_power": 385,
"max_power": 452,
"defense": 0,
"infusion_slots": [],
"infix_upgrade": {
"id": 142,
"attributes": [
{
"attribute": "Power",
"modifier": 85
},
{
"attribute": "Precision",
"modifier": 61
}
]
},
"suffix_item_id": 24547,
"secondary_suffix_item_id": ""
}
}
I do it like this:
Private Function Get_Name(id As Integer) As String
Dim httpObject As Object
Set httpObject = CreateObject("MSXML2.XMLHTTP")
sURL = "https://api.guildwars2.com/v2/items/" & id & "?lang=de"
sRequest = sURL
httpObject.Open "GET", sRequest, False
httpObject.send
sGetResult = httpObject.responseText
Dim oJSON As Object
Set oJSON = JsonConverter.ParseJson(sGetResult)
For Each sItem In oJSON
If sItem = "name" Then
Get_Name = oJSON(sItem)
End If
Next
End Function
That works fine, but i have one JSON i get from the API, that has a different Format and i dont manage to get this to work too.. It hast the following Format:
[
{
"id": 12134,
"category": 5,
"count": 204
},
{
"id": 12238,
"category": 5,
"count": 150
},
{
"id": 12147,
"category": 5,
"count": 146
},
{
"id": 12142,
"category": 5,
"count": 215
},
....
]
Thats my Try so Far:
Private Function Get_Anzahl_Im_Lager(id As Integer) As Integer
Dim httpObject As Object
Set httpObject = CreateObject("MSXML2.XMLHTTP")
sURL = "https://api.guildwars2.com/v2/account/materials?access_token=" & Tabelle2.Cells(1, 7)
sRequest = sURL
httpObject.Open "GET", sRequest, False
httpObject.send
sGetResult = httpObject.responseText
MsgBox sGetResult
Dim oJSON As Collection
Set oJSON = JsonConverter.ParseJson(sGetResult)
MsgBox oJSON
For Each sItem In oJSON
'If oJSON(sItem)("id") = id Then
' Get_Anzahl_Im_Lager = oJSON(sItem)("count")
' End If
Get_Anzahl_Im_Lager = sItem
Exit Function
Next
End Function
Problem is,according to the Debugger it parses the Array, but i just get an Empty Object back here, oJSON is empty, while sGetResult hast the JSON Data in it.
Any Solutions?
Made it.. Sometimes i should just start thinking from a new Point on :D
Private Function Get_Anzahl_Im_Lager(id As Integer) As Integer
Dim httpObject As Object
Set httpObject = CreateObject("MSXML2.XMLHTTP")
If Not IsEmpty(Tabelle2.Cells(1, 7)) Then
sURL = "https://api.guildwars2.com/v2/account/materials?access_token=" & Tabelle2.Cells(1, 7)
Else
Exit Function
End If
sRequest = sURL
httpObject.Open "GET", sRequest, False
httpObject.send
sGetResult = httpObject.responseText
Dim oJSON As Object
Set oJSON = JsonConverter.ParseJson(sGetResult)
Dim sItem, cnt&
For Each sItem In oJSON
cnt = cnt + 1
If oJSON(cnt)("id") = id Then
Get_Anzahl_Im_Lager = oJSON(cnt)("count")
Exit Function
End If
Next
End Function
The JSON objects are of two different types. One is dictionary and one is a collection. Use TypeName to determine which you are getting from the responseText and handle as required e.g.
Dim item As Long, oJSON As Object
Set oJSON = JsonConverter.ParseJson(sGetResult)
Select Case TypeName(oJSON)
Case "Collection"
For Each item In json
Debug.Print item("count")
Next
Case "Dictionary"
Debug.Print json("name")
End Select

Visual Basic Parsing Nested JSON file

So I have this nested JSON file
{
"root": [{
"STATUS_RE": {
"STATUS": {
"STATUS": {
"OWNER": "Manny",
"REQUEST_ID": "00000",
"STATE": "SUCCESS"
}
},
"RESPONSE_FORMAT": "New",
"OWNER": "Manny",
"REQUEST_ID": "00000",
"RESULT": [{
"USER": {
"BUSINESS_ID": "N",
"ID_NUMBER": "016",
"U_LANGUAGE": "F",
"B_CODE": "08302"
}
},
{
"USER_A": {
ROLE": "true",
"ACCESSING": "true"
}
}
}
}]
}
Im using this visual basic code trying to access certain part of this json file. For example I want "BUSINESS_ID" and "ID_Number" under "USER" and I also want "ROLE" under "USER_A"
This is the code I'm working with
Dim FSO As New FileSystemObject
Dim JsonTS As TextStream
Set JsonTS = FSO.OpenTextFile("example.json", ForReading)
JsonText = JsonTS.ReadAll
JsonTS.Close
Set JSON = ParseJson(JsonText)
i = 2
For Each Item In JSON
Sheets(1).Cells(i, 1).Value = Item("BUSINESS_ID")
Sheets(1).Cells(i, 2).Value = Item("ID_Number")
i = i + 1
I tried changing For Each Item In JSON to something like For Each Item In JSON("root")(STATUS_RE").... all the way to ("USER") then grab the "BUSINESS_ID" but that did not work, how would I extract the information I need.
For example:
Dim result As String
Dim JSON As Object
result = Range("A9").Value
Set JSON = JsonConverter.ParseJson(result)
Debug.Print JSON("root")(1)("STATUS_RE")("RESULT")(1)("USER")("ID_NUMBER") '>> 016

Deserialize malformed Json returning empty arrays

Please, I use VB.NET Http Requests to read data from a webservice. It used to send data this way:
[
{
"id": 7532,
"nome": "LABOR INC.",
"isClient": false,
"personality": {
"id": 2,
"value": "CORPORATION"
},
"registryNumbers": [
{
"id": 9378,
"number": "20786790174"
}
],
"personality_id": 2
},
{
"id": 7537,
"nome": "JOSE SILVA",
"isClient": false,
"personality": {
"id": 1,
"value": "PERSON"
},
"gender": {
"id": 1,
"value": "MALE"
},
"cityOfBirth": {
"id": 355030,
"value": "SAO PAULO"
},
"nationality": {
"id": 85,
"value": "BRAZILIAN"
},
"registryNumbers": [
{
"id": 9383,
"number": "03217495388"
}
],
"personality_id": 1
}
]
It was ok because unused fields (as "gender" and "cityOfBirth" for corporations) were omitted. Since some days, however, it started to send back these fields as empty arrays ([]), like this:
{
"id": 7532,
"nome": "LABOR INC.",
"isClient": false,
"personality": {
"id": 2,
"value": "CORPORATION"
},
"gender": [],
"cityOfBirth": [],
"nationality": [],
"registryNumbers": [
{
"id": 9378,
"number": "20786790174"
}
],
"personality_id": 2
}
And because of that it misfit the destiny properties in deserialization class, because these are not (and can't be) enumerations/arrays but single objects.
My question: is there some deserialization extension or attribute I can add to my classes in order to deserialize those ([]) as null/Nothing? Special thanks if it comes in VB.NET, but I'm able to read and adapt C# as well.
That is, I'd like to know how I could make my code halt when an array is "forced" into a property that expects single objects, and do the proper treatment at this point.
Tried and solved the problem with a custom converter:
Public Class BogusArrayJsonConverter
Inherits JsonConverter
Public Overrides Function CanConvert(objectType As Type) As Boolean
Return GetType(MyRecord).IsAssignableFrom(objectType)
End Function
Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object
If reader.TokenType = JsonToken.StartArray Then
Return serializer.Deserialize(Of MyRecord())(reader).SingleOrDefault
Else
Return serializer.Deserialize(Of MyRecord)(reader)
End If
End Function
Public Overrides Sub WriteJson(writer As JsonWriter, value As Object, serializer As JsonSerializer)
Throw New NotImplementedException()
End Sub
End Class
Thanks to all who tried to help me.

Resources