How to simplify this code using newtonsoft or other json parsers? - json

I got a simple json
{"200567175963759": { "pair": "esp_btc", "type": "sell", "amount": 2000000, "rate": 1E-08, "timestamp_created": "1498114417", "status": 0}}
I want to parse it without creating any new classes. I want to make it easy.
I am using jsonhelper class that I created my self to parse it. It's basically try to find the first thing between two double quotes and got 200567175963759 which is the order id. Get parameter is simply finding something between "pair":" and "
For simple json it works fine. How can I do get order ID, which si 200567175963759, or timestamp, using better parser, like newtonsoft.
I wonder if I can do that using newtonsoft json?
Dim jsonstring = jsonHelper.stripWhiteSpace(order3.ToString) '{"200567175963759": { "pair": "esp_btc", "type": "sell", "amount": 2000000, "rate": 1E-08, "timestamp_created": "1498114417", "status": 0}}
Dim orderid = fGetToken(order3.ToString, 1, """", """")
Dim base = b
Dim quote = key
Dim typeOfOrder = jsonHelper.getParameter(jsonstring, "type")
Dim amount = jsonHelper.getParameter(jsonstring, "amount")
Dim rate = jsonHelper.getParameter(jsonstring, "rate")
Dim timestamp_created = jsonHelper.getParameter(jsonstring, "timestamp_created")
Dim order4 = OrdersAtExchange.createOrders(amount, base, quote, _exchange, timestamp_created, rate, orderid)
_orders.Add(order4)
If I try to parse that using newtonsoft, I got this object whose type is
Dim order = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonorders)
Dim order1 = CType(order, Newtonsoft.Json.Linq.JObject)
Dim order2 = order1.Item("return").ToList
I look at all the method in Newtonsoft.Json.Linq.JObject I can't find anything that say convert dictionary structures in json to say generic.dictionary
There is something like that. I tried but simply didn't work.
So I wonder if there's an actual sample of some code parsing that simple json with newtonsoft?

Object is Type Dictionary, In case if property looks like index or key it probably dictionary
Dim JsonString As String = "{""200567175963759"": { ""pair"": ""esp_btc"", ""type"": ""sell"", ""amount"": 2000000, ""rate"": 1E-08, ""timestamp_created"": ""1498114417"", ""status"": 0}}"
Dim JsonSettings = New Newtonsoft.Json.JsonSerializerSettings
JsonSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore
Dim OutObject = Newtonsoft.Json.JsonConvert.DeserializeObject(Of Dictionary(Of String, SampleType))(JsonString)
Class SampleType
Property pair As String
Property type As String
Property amount As String
Property rate As String
Property timestamp_created As String
Property status As String
End Class

Here is a sample showing how you can parse your JSON using Json.Net's LINQ-to-JSON API (JTokens, JObjects, etc.)
Dim json As String =
"{" &
" ""200567175963759"": {" &
" ""pair"": ""esp_btc""," &
" ""type"": ""sell""," &
" ""amount"": 2000000," &
" ""rate"": 1E-08," &
" ""timestamp_created"": ""1498114417""," &
" ""status"": 0" &
" }" &
"}"
Dim rootObject As JObject = JObject.Parse(json)
For Each prop As JProperty In rootObject.Properties()
Dim orderid As String = prop.Name
Dim orderInfo As JObject = prop.Value
Dim pair As String = orderInfo("pair").ToString()
Dim typeOfOrder As String = orderInfo("type").ToString()
Dim amount As Decimal = orderInfo("amount").ToObject(Of Decimal)
Dim rate As Decimal = orderInfo("rate").ToObject(Of Decimal)
Dim timestamp_created As String = orderInfo("timestamp_created").ToString()
Dim status As Integer = orderInfo("status").ToObject(Of Integer)
'etc. ...
Next
Demo: https://dotnetfiddle.net/X9SPIE

Related

How to retrieve the value of "Quotes" in this json format?

I'm trying to build an app where I can retrieve live Currency values online.
I was using apilayer and I successfully retrieved the data I wanted except for the final currency value.
I'm not sure how to read the value inside the "quotes" node.
Jason Result from API:
{
"success":true,
"terms":"https:\/\/currencylayer.com\/terms",
"privacy":"https:\/\/currencylayer.com\/privacy",
"timestamp":1514567346,
"source":"USD",
"quotes":{
"USDPHP":49.950001
}
}
Using this:
Dim req As HttpWebRequest
Dim res As HttpWebResponse = Nothing
Dim rdr As StreamReader
req = DirectCast(WebRequest.Create("http://apilayer.net/api/live?access_key=xxKeyRemovedxx&currencies=PHP&format=1"), HttpWebRequest)`
res = DirectCast(req.GetResponse, HttpWebResponse)
rdr = New StreamReader(res.GetResponseStream)
Dim jsonresp As String = rdr.ReadToEnd
Dim jResuldict = JsonConvert.DeserializeObject(Of Dictionary(Of String, `Object))(jsonresp)`
Dim qts = jResuldict.Item("quotes").ToString
MsgBox(qts)
Result is:
{
"USDPHP":49.950001
}
I wanted to retrieve only the value inside USDPHP which is 49.95.
So that I can use that value for conversion.
What am I missing?
It looks like quotes is a nested dictionary of name/decimal pairs. To extract it, you can parse your JSON string to a JToken hierarchy, pick out the "quotes" property with SelectTokens(), then deserialize its value with JToken.ToObject(of Dictionary(of String, Decimal))(). Having done so you can work with as you would with any dictionary, for instance by looping through its key/value pairs with For Each:
' Extract and deserialize quotes dictionary
Dim quotes as Dictionary(of String, Decimal) = JToken.Parse(jsonresp) _
.SelectTokens("quotes") _
.Select(Function(d) d.ToObject(of Dictionary(of String, Decimal))()) _
.SingleOrDefault()
' Show quotes to the user
Console.WriteLine(If(quotes.Count = 1, "There is 1 quote: ", string.Format("There are {0} quotes", quotes.Count)))
For Each pair in quotes
Dim name as String = pair.Key
Dim quote as Decimal = pair.Value
Console.WriteLine(" Quote for {0} is {1}.", name, quote)
Next
Which outputs
There is 1 quote:
Quote for USDPHP is 49.950001.
If you are sure that one and only one "quotes" token will be present, you can simplify that a bit by using SelectToken() rather than SelectTokens():
' Extract and deserialize quotes dictionary
Dim quotes as Dictionary(of String, Decimal) = JToken.Parse(jsonresp) _
.SelectToken("quotes") _
.ToObject(of Dictionary(of String, Decimal))()
Finally, if you happen to know the name USDPHP in advance you can pick out its specific value with SelectToken() then cast it to Decimal with an explicit cast:
Dim quote as Decimal = CType(JToken.Parse(jsonresp).SelectToken("quotes.USDPHP"), Decimal)
Sample working .Net fiddle.
Try this, i have not tested it but it should work
Dim qts = jResuldict.Item("quotes.USDPHP").ToString
MsgBox(qts)

deserialize JSON without one by one, multiple properties

I have this JSON:
{"JOE":{"id":7,"age":"23"},"BILLY":{"id":8,"age":"29"}}
i have this solution for a more simple JSON structure posted by RajN.
Dim j1 As String = "{ "JOE"":""0.90000000"",""JOE"":""3.30000000"",""MONROE"":""1.20000000""}"
Dim dict = JsonConvert.DeserializeObject(Of Dictionary(Of String, String))(j1)
For Each kvp In dict
Console.WriteLine(kvp.Key & " - " + kvp.Value)
Next
I'm looking for how to do with the new JSON data.
Thanks in advance
The solution very is nearly the same as the other solution you linked by #RajN, except instead of using Dictionary(Of String, String) you need to use Dictionary(Of String, T) where T is a class that you define to hold id and age.
So, define a class:
Public Class PersonData
Public Property id As Integer
Public Property age As String
End Class
Then deserialize:
Dim json As String = "{""JOE"":{""id"":7,""age"":""23""},""BILLY"":{""id"":8,""age"":""29""}}"
Dim dict = JsonConvert.DeserializeObject(Of Dictionary(Of String, PersonData))(json)
For Each kvp In dict
Console.WriteLine("name: " & kvp.Key)
Console.WriteLine("id: " & kvp.Value.id)
Console.WriteLine("age: " & kvp.Value.age)
Console.WriteLine()
Next
Fiddle: https://dotnetfiddle.net/HMv7Om
Make sense?

Get json value in VB.NET

How can I get the name of a key in a json file? I have a json that I'm parsing in VB.NET and one of the 'fields' have a dynamic name (it changes). What could I do to get the key name?
For example:
...
"one":{
"two":{
"example":[
{
"aaa":"test",
"bbb":"test",
"ccc":"test"
},
...
I'm getting correctly all the values (test, test, test...) and the keys 'one', 'two', have always the same name. But the key 'example' changes the name according the json file information. How could I identify the key text?
I wrote a piece of code that converts JSON into a XDocument here: https://github.com/dday9/.NET-JSON-Transformer
If you were to use that code, then you could get the node that represents your "two" object and then get the first child node in to. By doing this, you're essentially getting the array by an Index instead of by a name.
Here is a quick example of what I mean:
Dim literal As String = "{""two"":{""example"":[{""aaa"":""test"",""bbb"":""test"",""ccc"":""test""}]}}"
Dim xJSON As XDocument = JSON.Parse(literal)
Dim object_two As XElement = xJSON.Descendants("two").FirstOrDefault()
If object_two IsNot Nothing Then
Dim first_descendent As XElement = object_two.Descendants().Skip(1).FirstOrDefault()
If first_descendent IsNot Nothing Then
Console.WriteLine(first_descendent)
End If
End If
Fiddle: Live Demo
This piece will allow to get data from an unknown JSON structure, without having to define a class.
Sample
Dim serializer As System.Web.Script.Serialization.JavaScriptSerializer
serializer = New JavaScriptSerializer()
' {"elements":[{"handle~":{"emailAddress":"myself#example.com"},"handle":"urn:li:emailAddress:348955221"}]}
dim json as string
Dim obj As System.Collections.Generic.IDictionary(Of String, Object)
obj = serializer.Deserialize(Of System.Collections.Generic.IDictionary(Of String, Object))(json)
dim email as string=string.empty
email = If(GetJsonValue(obj, {"elements", "handle~", "emailAddress"}.ToList()), email)
The Function, very self descriptive:
''' <summary>decode json data </summary>
Public Function GetJsonValue(ByVal obj As Object,
ByVal key As List(Of String)) As String
GetJsonValue = Nothing
' If the object is an array, assume any element can contain the key
If obj.GetType Is GetType(Object()) Then
For Each newObj As Object In CType(obj, Object())
Dim tmp As String = GetJsonValue(newObj, key)
If Not String.IsNullOrEmpty(tmp) Then Return tmp
Next
Else
Dim objEle As System.Collections.Generic.IDictionary(Of String, Object)
Dim keyName As String
Dim objKey As String
'
keyName = key(0)
objEle = CType(obj, System.Collections.Generic.IDictionary(Of String, Object))
objKey = objEle.Keys.ToArray()(0)
If objEle.ContainsKey(keyName) Then
Dim temp As Object = objEle.Item(keyName)
If key.Count > 1 Then
' if the element is array, we need to get the array element and move to the next
key.RemoveAt(0)
Return GetJsonValue(temp, key)
Else
Return temp.ToString()
End If
End If
End If
End Function
I see this is solved but would like to suggest another solution for future readers. The JavaScriptSerializer can return a nested dictionary collection (Of String, Object). I find it easier to explore the result in debug while coding. The code below shows an example of how to navigate the collections.
Dim deserializer As New System.Web.Script.Serialization.JavaScriptSerializer
Dim text As String = "{""two"":{""example"":[{""aaa"":""test"",""bbb"":""test"",""ccc"":""test""}]}}"
Dim dict As Dictionary(Of String, Object) = deserializer.DeserializeObject(text)
Dim keys As Dictionary(Of String, Object).KeyCollection
keys = dict("two")("example")(0).Keys
Dim aaaName As String = keys(0)
Dim aaaValue As String = dict("two")("example")(0)(aaaName)

Serializing from object to JSON

I'm consuming a web service in some legacy applications written in VB6. Right now I've been able to parse the JSON returned from a web service using the VB JSON parser found here: http://www.ediy.co.nz/vbjson-json-parser-library-in-vb6-xidc55680.html
However, I'm still hardcoding the JSON string that gets passed into the POST request payload.
Generically speaking:
result = WebRequestPost(url, "{""Id"":""" & productId & """,""Name"":""" & productName & """,""Category"":""" & productCat & """,""Price"":""" & productPrice & """}")
Is there a cleaner way that I can generate a JSON payload based on an object?
I ended up building my own assembler of sorts...
Dim jsonArray() As String
'_______________________________________________________________
'Initializes the opening and closing braces of the JSON payload
Public Sub JSONInitialize()
ReDim jsonArray(1)
jsonArray(0) = "{"
jsonArray(1) = "}"
End Sub
'_______________________________________________________________
'Adds a string value to the JSON payload
Public Sub JSONAddString(nFieldName As String, nValue As String)
Dim temp As String
temp = jsonArray(UBound(jsonArray))
Dim index As Integer
index = UBound(jsonArray)
ReDim Preserve jsonArray(UBound(jsonArray) + 1)
jsonArray(UBound(jsonArray)) = temp
jsonArray(index) = """" & nFieldName & """:""" & nValue & ""","
End Sub
'_______________________________________________________________
'Adds an integer value to the JSON payload
Public Sub JSONAddInt(nFieldName As String, nValue As Integer)
Dim temp As String
temp = jsonArray(UBound(jsonArray))
Dim index As Integer
index = UBound(jsonArray)
ReDim Preserve jsonArray(UBound(jsonArray) + 1)
jsonArray(UBound(jsonArray)) = temp
jsonArray(index) = """" & nFieldName & """:" & nValue & ","
End Sub
So (sanitized) execution ends up looking like:
Dim o As New MyObject
Call o.JSONInitialize
Call o.JSONAddString("My JSON String Field", "Test String Value")
Call o.JSONAddInt("My JSON Int Field", 25)
o.JSONSerialize() returns:
{"My JSON String Field":"Test String Value","My JSON Int Field": 25,}
Unfortunately it puts the comma at the end so it won't win any beauty contests but the API I'm calling doesn't care.

VBA access to a json property without name property

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