Parse multiple JSON/VBA objects with VBA-JSON - json

I have the following JSON response:
[
{
"id": 1354345345,
"date": "2021-10-01T23:29:42.000000+02:00",
"count": 0,
"year": 2020,
"area": 232,
"numberList": [
8693978
],
"Property": {
"PropertyID": 135005860000118,
"PropertyNumber": 2244
}
},
{
"id": 2345235345,
"date": "2021-02-13T13:40:30.000000+01:00",
"count": 2,
"year": 2020,
"area": 122,
"numberList": [
8693978
],
"Property": {
"PropertyID": 153005860001536,
"PropertyNumber": 1555
}
}
]
Inside the array [], there can be several object {}, each with a value in "area". In this example, there are two objects in the array.
I am trying to parse the JSON via VBA-JSON.
I've tried the following VBA code, but it will only return the names of each object item and not the value.
Set Json = JsonConverter.ParseJson(responseText)
For Each Item In Json
For Each i In Item
Debug.Print i
Next
Next
VBA debug console will show:
id
date
count
year
area
numberList
Property
id
date
count
year
area
numberList
Property
How do I fetch the area of each object?

JsonConverter.ParseJson(responseText) creates an object keeping Scripting Dictionaries... So, they expose keys and items. Based on that logic, please try the next way of "area" values extracting:
The string you show misses a ":" character (replaced with ";").Here: "area"; 232,. It should be correct to be parsed...
The next code version will iterate between the object keys and items, extracted the value (item) for the key "area":
Dim json As Object, strFile As String, responseText As String, dict, i As Long
responseText = "the corrected string you show..."
Set json = JsonConverter.ParseJSON(responseText)
For Each dict In json
For i = 0 To dict.count - 1
If dict.Keys()(i) = "area" Then
Debug.Print TypeName(dict), TypeName(dict.Keys()(i)), TypeName(dict.Items()(i))
Debug.Print dict.Items()(i)
End If
Next i
Next dict

Related

Access nested values in JSON-Object in VBA

I would like to get data from a JSON-Object, that I got from a Rest-API, with VBA to display some data into an Excel-Worksheet. I'm using the library (VBA-JSON v2.3.1 JsonConverter).
I have the following JSON-Object:
{
"devices": [
{
"data": [
{
"id": 0,
"name": "Hello"
},
{
"id": 1,
"name": "How are you?"
},
{
"id": 2,
"name": "Bye"
}
],
"type": "LORA"
}
],
"includedTypes": [
"LORA"
]
}
I want to get the objects in the array from "data".
My VBA-Code is this:
Dim js1Object As Object
Dim response1 As String
strUrl = "https://XXXXXXXXXXXdevices
Set hReq = CreateObject("MSXML2.XMLHTTP")
With hReq
.Open "GET", strUrl, False
.SetRequestHeader "Authorization", "Bearer " & apitoken
.Send
response1 = hReq.responseText
MsgBox response1
Set js1Object = JsonConverter.ParseJson(response1)
j = 31
For Each item In js1Object("devices")
ws.Cells(j, 7) = item("id")
ws.Cells(j, 10) = item("name")
j = j + 1
Next
MsgBox (response1)
End With
How can I access the values from "data"?
If the JSON would look like the object below, my code would work. But my problem is, that the response that I get, is more nested and I can't directly access "data".
{
"devices": [
{
"id": 0,
"name": "Hello"
},
{
"id": 1,
"name": "How are you?"
},
{
"id": 2,
"name": "Bye"
}
]
}
I just don't know, how to access deeper values in JSON-Object. The solutions from similar questions with print are not working with my code.
Thanks for helping me!
Your "root" json object is a Dictionary - the key "devices" is a Collection object, and the first element is another dictionary with two keys "data" and "type".
"data" is another Collection of Dictionaries, so you can do this to get to the contained id and name values:
Dim Json As Object, data, d
'reading json from a worksheet cell...
Set Json = JsonConverter.ParseJson(Range("A5").Value)
Set data = Json("devices")(1)("data") 'Dictionary key->Collection index->Dictionary key
For Each d In data
Debug.Print d("id"), d("name")
Next d
Output:
0 Hello
1 How are you?
2 Bye

deserialize json into vb.net class with conditional definition

I am an intermediate programmer and am trying to find a solution to a JSON deserialize issue in vb.net. I'm working some product updates with an API (not mine) in which I have to get the product, deserialize it, change some values, and post an update.
I have built out a bunch of vb.net classes to handle the deserialize (newtonsoft.json) of a JSON doc and for the most part works great. However, I ran into a situation on some products where the object could be defined one of two ways depending on the value of a particular json object.
Here is a snippet of the JSON:
"PriceGrids": [
{
"IsBasePrice": false,
"PriceConfigurations": [
{
"Criteria": "Imprint Method",
"Value": [
"SILKSCREEN"
]
}
]
},
{
"IsBasePrice": true,
"PriceConfigurations": [
{
"Criteria": "Size",
"Value": [
{
"Attribute": "Length",
"Value": "25",
"Unit": "cm"
},
{
"Attribute": "Width",
"Value": "7.5",
"Unit": "cm"
},
{
"Attribute": "Height",
"Value": "14.5",
"Unit": "cm"
}
]
}
]
}
So Value has two definitions depending on the IsBasePrice value (true/false). I currently have Value defined in the class as below.
Private _Value As New List(Of String)
Public Property Value() As List(Of String)
Get
Return _Value
End Get
Set(value As List(Of String))
_Value = value
End Set
End Property
This, of course, fails when it isn't a list of string(s). I can't find an example anywhere of handling this. Is it even possible in vb.net to handle a conditional object definition based on the Json provided?

Extract values from a parsed json object using a function node or split & switch node in NODE.red

Was trying to extract values from a parsed json object using a function node or split & switch node, tried to many ways and nothing seems to work fro me.
the example below I would like to have 5 outputs for the text and numeric values.
here is my payload in json:
{
"applicationID": "1",
"applicationName": "test_ds18b20",
"deviceName": "arduino_uno",
"devEUI": "1234567890123456",
"rxInfo": [
{
"mac": "aa755a0048050130",
"rssi": -57,
"loRaSNR": 10,
"name": "raspberry_pi",
"latitude": 1.466860686785175,
"longitude": 2.019478797912605,
"altitude": 0
}
],
"txInfo": {
"frequency": 868100000,
"dataRate": {
"modulation": "LORA",
"bandwidth": 125,
"spreadFactor": 7
},
"adr": true,
"codeRate": "4/5"
},
"fCnt": 9,
"fPort": 1,
"data": "Z29vZGJ5ZQ==",
"object": {}
}
first i try with function node to extract "data", but it returns array like this:
0: ""data":"Z29vZGJ5ZQ==""
1: "Z29vZGJ5ZQ=="
i dont need array i need string
function:
var regexsearch = /\"data\":\"(.*?)\"/i;
var my = msg.payload.match(regexsearch);
msg.payload = my;
return msg;
but i need to get only this Z29vZGJ5ZQ==
than i try with split & switch nodes and gets the whole linelike this: ""data":"Z29vZGJ5ZQ==""
but i need to get only this Z29vZGJ5ZQ==
and here is my flow:
[{"id":"d46d38e2.27cc78","type":"inject","z":"ff592a31.cf21a8","name":"","topic":"","payload":"{\"applicationID\":\"1\",\"applicationName\":\"test_ds18b20\",\"deviceName\":\"arduino_uno\",\"devEUI\":\"1234567890123456\",\"rxInfo\":[{\"mac\":\"aa755a0048050130\",\"rssi\":-57,\"loRaSNR\":10,\"name\":\"raspberry_pi\",\"latitude\":48.466860686785175,\"longitude\":35.019478797912605,\"altitude\":0}],\"txInfo\":{\"frequency\":868100000,\"dataRate\":{\"modulation\":\"LORA\",\"bandwidth\":125,\"spreadFactor\":7},\"adr\":true,\"codeRate\":\"4/5\"},\"fCnt\":9,\"fPort\":1,\"data\":\"Z29vZGJ5ZQ==\",\"object\":{}}","payloadType":"json","repeat":"","crontab":"","once":false,"x":90,"y":160,"wires":[["1a34819e.743eee"]]},{"id":"105db6d9.0df1c9","type":"debug","z":"ff592a31.cf21a8","name":"","active":true,"console":"false","complete":"false","x":610,"y":100,"wires":[]},{"id":"1ac8a3e1.8f379c","type":"split","z":"ff592a31.cf21a8","name":"","splt":",","spltType":"str","arraySplt":"1","arraySpltType":"len","stream":false,"addname":"","x":250,"y":340,"wires":[["c10ec515.102d38"]]},{"id":"c10ec515.102d38","type":"switch","z":"ff592a31.cf21a8","name":"","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"\"data\":","vt":"str"},{"t":"cont","v":"\"latitude\":","vt":"str"}],"checkall":"true","outputs":2,"x":370,"y":340,"wires":[["105db6d9.0df1c9"],["6b2d5d19.7868e4"]]},{"id":"1a34819e.743eee","type":"json","z":"ff592a31.cf21a8","name":"","pretty":false,"x":115.55555555555556,"y":312.22222222222223,"wires":[["1ac8a3e1.8f379c","bae9fa5d.a9f238"]]},{"id":"bae9fa5d.a9f238","type":"function","z":"ff592a31.cf21a8","name":"match","func":"var regexsearch = /\\\"data\\\":\\\"(.*?)\\\"/i;\nvar my = msg.payload.match(regexsearch);\nmsg.payload = my;\nreturn msg;","outputs":1,"noerr":0,"x":310,"y":160,"wires":[["105db6d9.0df1c9"]]},{"id":"6b2d5d19.7868e4","type":"debug","z":"ff592a31.cf21a8","name":"","active":true,"console":"false","complete":"false","x":610,"y":180,"wires":[]}]
Thanks for help

JSON serialization technicalities in VB.NET

What is the difference between the following serialization methods?
First Method
JsonConvert.SerializeObject(list or datatable)
and the output is
i.e. (3) [Object, Object, Object]
Second Method
Dim parent = Prtdata
Dim lGridColumns = New With {
Key .data = parent
}
Dim Setting = New JsonSerializerSettings
Setting.PreserveReferencesHandling = PreserveReferencesHandling.Objects
Dim jsonObject = JsonConvert.SerializeObject(lGridColumns, Formatting.Indented)
Return jsonObject
and its output is
{
"data": [
{
"RecID": 2383,
"PrtStatus": 0,
"PtFilenum": 15090248,
"PrtFilenum": 13090701,
"FullName": "asdasd",
"DOB": "04 Oct 1985"
},
{
"RecID": 3387,
"PrtStatus": 1,
"PtFilenum": 15090248,
"PrtFilenum": 15120996,
"FullName": "marwam mohmmad saleem",
"DOB": "24 May 2017"
},
{
"RecID": 3388,
"PrtStatus": 1,
"PtFilenum": 15090248,
"PrtFilenum": 170227111,
"FullName": "asd dsf as a",
"DOB": "27 Feb 2017"
}
]
}
why the output looks different in the browser console?
As the first comment, you can find a Serialization Guide on the website of NewtonSoft.json, in my answer I just provide a more elaborate version of my comment earlier.
The first scenario, where you are serializing something implemented IEnumerable (eg: list, array), will be represented by an array in Json, eg:
[{ "property": "value", "id": 0 }, {"property": "value", "id": 1}]
For the second scenario, you are doing several things differently, for example you are providing the PreserveReferencesHandling in the JsonSerializerSettings which would also preveserve any references made in the objects you are serializing, eg:
[{"$id": 1, "title": "item1"}, {"$id": 2, "title": "item2", "previous": { "$ref": 1 }]
This would make sure that when deserialized, the second object would contain a reference to the first object, inside the property previous.
Another thing you are doing differently is providing the Formatting.Indented, which will create a more reader friendly json document, having line breaks and indentation. The previous Json would then become something similar to this:
[{
"$id": 1,
"title": "item1"
},
{
"$id": 2,
"title": "item2",
"previous": {
"$ref": 1
}
}]
And, the last big difference is that in the last example, you are serializing a single object, cause it's public properties to be serialized, eg:
{
"data": [
...
]
}
Where data is a property on the object you are serializing.

Iterating through nested objects with VBJSON

I am attempting to connect to the SmartSheet API through VBA to pull the contents into an Excel sheet. I found the VBJSON library which has helped me a bit but I am struggling with iterating through the objects and pulling specific values.
I want to access the contents of the "Value" attribute for each row then do the same for subsequent rows. My biggest problem is that I do not know how this VBJSON library works since I cannot find any documentation on it and there are only a few examples and they deal with relatively straightforward JSON examples.
Desired Output
Row 1 Column 1 Content | Row 1 Column 2 Content
Row 2 Column 1 Content | Row 2 Column 2 Content
JSON
{
"id": 1,
"name": "Sheet Name",
"columns": [
{
"id": 1,
"index": 0,
"title": "Title of Column",
"type": "TEXT_NUMBER",
"primary": true
},
{
"id": 2,
"index": 1,
"title": "Title of Second Column",
"type": "TEXT_NUMBER"
},
],
"rows": [
{
"id": 1,
"rowNumber": 1,
"cells": [
{
"type": "TEXT_NUMBER",
"value": "Row 1 Column 1 Content",
"columnId": 1,
},
{
"type": "TEXT_NUMBER",
"value": "Row 1 Column 2 Content",
"columnId": 2,
},
],
"locked": true,
"lockedForUser": true,
"expanded": true,
"createdAt": "2013-10-11T13:43:24-05:00",
"modifiedAt": "2013-11-12T15:13:54-06:00"
},
{
"id": 2276445193037700,
"rowNumber": 2,
"cells": [
{
"type": "TEXT_NUMBER",
"value": "row 2 column 1 content",
"columnId": 1,
},
{
"type": "TEXT_NUMBER",
"value": "row 2 column 2 content",
"columnId": 2,
}
]
}
VBJSON library
http://www.ediy.co.nz/vbjson-json-parser-library-in-vb6-xidc55680.html
Below is code I've pieced together from what I could find online and right now it pulls the values associated with each attribute in the row. But I only need to pull the contents of the "Value" portion and I can't seem to figure out how to do that. I think I really just need help with my for loop because I have the JSON, I have a library that appears to work, I am just struggling to figure out how to combine it all.
Dim xmlHttp As Object
Set xmlHttp = CreateObject("MSXML2.ServerXMLHTTP.6.0")
xmlHttp.Open "GET", URl, False
xmlHttp.setRequestHeader "Content-Type", "text/xml"
xmlHttp.send
Dim strDiv As String, startVal As Long, endVal As Long
strDiv = xmlHttp.ResponseText
startVal = InStr(1, strDiv, "rows", vbTextCompare)
endVal = InStr(startVal, strDiv, "]", vbTextCompare)
strDiv = "{" & Mid(strDiv, startVal - 1, (endVal - startVal) + 2) & "}"
Dim JSON As New JSON
Dim p As Object
Set p = JSON.parse(strDiv)
i = 1
For Each Item In p("rows")(1)("cells")(1)
Cells(2, i) = p("rows")(1)("cells")(1)(Item)
i = i + 1
Next
Ran into a similar problem, see my answer here: https://stackoverflow.com/a/16825736/1240745
This library has been a life-saver for me: https://github.com/VBA-tools/VBA-JSON (previously https://code.google.com/p/vba-json/)
I use it in a library I wrote for accessing Salesforce, Trello, and a few others. (Shameless plug): https://github.com/VBA-tools/VBA-Web
Using the VBA-JSON library, it would involve something like the following:
Dim Parsed As Dictionary
Set Parsed = JsonConverter.ParseJson(xmlHttp.ResponseText)
' Object -> Dictionary, so Row and Cell: Dictionary
Dim Row As Dictionary
Dim Cell As Dictionary
' Array -> Collection, so Parsed("rows"): Collection
For Each Row In Parsed("rows")
For Each Cell In Row("cells")
' Access Dictionary items by key
Cells(Row("rowNumber"), Cell("columnId")) = Cell("value")
Next Cell
Next Row
(or something similar)