How to deserialize theefold nested json data? - json

Consuming a RestAPI I get a Json file that holds data of surveys. I load the file into the following class:
Public Class GeneralInfo
Public Property id As Integer
Public Property name As String
Public Property data As List(Of FullData)
End Class
Every survey has an id, a name and data.
Public Class FullData
Public Property userID As ULong
Public Property data As List(Of String)
End Class
Every survey holds data for each participant. I use Newtonsoft.Json to get the data into my classes.
JsonConvert.DeserializeObject(Of List(Of GeneralInfo))(jstr)
The data within the data-property is comma separated but the length is different for every survey. So in survey 1 can be 100 datapoints (one for each answer to a question) and in survey 2 can be up to 400 datapoints. A few of these datapoints can include comma as well since there are datapoints that hold open questions.
I just do not know how to store these data properly. I already read into the JsonConvert and could accomplish getting the data into the classes you can see above but here it ends. Could anyone help me out here? I address these to c# as well since I do not care if the solution is c# or vb.net.
Here are some sample data:
[{"id":1,
"name":"2015 - companyname.dpt",
"data":[{
"userId":364,
"data":["367","90","company","","","Anonymous","User","anonymous#provider.org","","100.100.100.100","14242","undefined","0","7891","2","2","3","1","","","","","","","2015","1","","","","","","","","","","","","","","","","3","3","2","1","3","3","3","4","3","3","4","2","3","3","2","3","2","3","4","3","","4","5","3","4","2","4","4","4","4","4","2","4","4","2","2","4","3","4","4","4","4","3","","1","1","1","5","1","1","1","","1","1","1","1","1","3","3","3","3","4","4","1","","","","2","2","3","1","","","","","","","","",""]
}, {"userID": 365, ...}]
}]

Related

How to deserialize Json with fix named elements dynamically in vb.net?

I’m on the way to implement an interface to the Ameritrade Rest API in a vb.net application (with httpclient).
Amongst other things, I have to query quotes from a ticker list (e.g. AMD,MSFT,AMZN, ....).
The call of the API works without problems, I get a valid Json back, but the Json is not given back in a way, I would expect.
I now search the best way to handle that problem...
This is not the first interface to a Rest API, I have implemented.
Normally, I implement a corresponding data class in vb.net and then use JsonConvert (from Newtonsoft) to deserialize the Json string into my data class.
Example:
Dim oObject As New DataClass
oObject = JsonConvert.DeserializeObject(Of DataClass)(JsonString)
whereby DataClass is the vb.net class that is defined according to the data in the Json string.
Problem:
The ticker symbol-list to query is dynamic and can change from api call to api call.
If I - e.g. - query AMD and MSFT in a call, I get back (cut to only a few fields) the following Json:
{
"AMD": {
"assetType": "EQUITY",
"symbol": "AMD",
"description": "Advanced Micro Devices, Inc. - Common Stock",
"bidPrice": 92.11
},
"MSFT": {
"assetType": "EQUITY",
"symbol": "MSFT",
"description": "Microsoft Corporation - Common Stock",
"bidPrice": 243.1
}
}
To be able to deserialize the Json, I would have to implement the following DataClass:
Public Class DataClass
Public Property AMD As AMD
Public Property MSFT As MSFT
End Class
Public Class AMD
Public Property assetType As String
Public Property symbol As String
Public Property description As String
Public Property bidPrice As Double
End Class
Public Class MSFT
Public Property assetType As String
Public Property symbol As String
Public Property description As String
Public Property bidPrice As Double
End Class
This would work but is absolutely static and does not make any sense, as I would have to implement a (identical) class for any ticker, I maybe want to query in the feature.
I would expect to get back a dynamic list so that I could implement the class as following:
Public Class DataClass
Public Property TickerDetails As List(Of TickerDetail)
End Class
Public Class TickerDetail
Public Property assetType As String
Public Property symbol As String
Public Property description As String
Public Property bidPrice As Double
End Class
This way, I would be able to deserialize in a List of TickerDetails and the go thru the list (no matter, which symbols I queried).
But, I can’t change, what I get back over the API...
Question:
What is the best way to handle this problem?
You should create a class to represent the a generic stock and then use DeserializeObject to deserialize it into a Dictionary(Of String, [classname]) where the Key represents the stock symbol and the value represents the class.
Take a look at this example:
Public Class Stock
Public Property assetType As String
Public Property symbol As String
Public Property description As String
Public Property bidPrice As Double
End Class
'...
Dim stocks = JsonConvert.DeserializeObject(Of Dictionary(Of String, Stock))(response)
Example: Live Demo
First thanks for the comments.
I ended up to do it completely different now...
I had further problems with the Ameritrade API:
Some fields are named with leading numbers (52WkHigh and 52WkLow) and
vb.net dev's know, that VB.net don't like properties in classes that
are named with a leading number
So I had to "patch" the received Json data and change the names on the fly to other names ("52WkHigh" to "dble52WkHigh" and "52WkLow" to "dble52WkLow") to be able to deserialize
over the data class, what is not nice
Further, I finally need the data (as fast as possible) in a data table and had "a long way to go":
get data -> deserialize to the data class -> walk thru the data class and overtake the data in the data table.
So.. my new solution (with JObject):
Note: needs:
Imports Newtonsoft.Json.Linq
Code snippets:
Create data table in memory:
Dim dtErgebnis As New DataTable
Dim drTemp As DataRow
With dtErgebnis.Columns
.Add("symbol", System.Type.GetType("System.String"))
.Add("lastPrice", System.Type.GetType("System.Double"))
.Add("lastSize", System.Type.GetType("System.Int32"))
.Add("quoteTime", System.Type.GetType("System.DateTime")) ' Note: is a Long in Json
...
End With
Parse the Json-String and fill the datatable:
get the data over httpclient (in JsonString)...
Dim oJson As JObject = JObject.Parse(JsonString) ' creates children tokens
Dim results As List(Of JToken) = oJson.Children().ToList
For Each item As JProperty In results
item.CreateReader()
drTemp = dtErgebnis.NewRow() ' create a new row to data table in memory
' Fill the fields
drTemp("symbol") = item.Value("symbol")
drTemp("lastPrice") = item.Value("lastPrice")
drTemp("lastSize") = item.Value("lastSize")
drTemp("quoteTime") = GetUTCDateFromTimeStamp(item.Value("quoteTimeInLong")).AddHours(1) ' original Long
...
' Add the new row to the data table
dtErgebnis.Rows.Add(drTemp)
' Save the changes
dtErgebnis.AcceptChanges()
Next
Additional note: The Ameritrade API gives back the time stamps as long (additional hurdle), but I (and I think also you;-) want it as datetime.
Therefore the Long (I think this data type comes from Java/Unix) has to be "translated" to datetime = vb.net function GetUTCDateFromTimeStamp below:
Public Function GetUTCDateFromTimeStamp(TimeStamp As Long) As DateTime
Static startTime As New DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)
Return startTime.AddMilliseconds(TimeStamp)
End Function
Additional note:
As I want to have the Swiss time, I add one hour to the UTC time.
So.. this a real good solution for me (exactly for the Ameritrade API).
And.. it's blazing fast... (I get 19 tickers with all fields and show the result (data table) in a data grid).
All together took < 1 Second ("felt" about 500 ms)
Hope this helps somebody...

Get Datatype of Json Entries

I get a Json file from our data provider without any information about the datatype of the data inside. The Json comprises only the data and one entry looks like this (this is survey data and one entry is the data of one person):
{"data":["4482359","12526","2014 Company Y","2","3","1"]}
I deserialized the file and have it within an object now but all entries are strings. I want to import it into a database but each entry should have the datatype that it best fits to it. E.g. 1 is int16, 2014 Company Y is string. Acutally I have only Int16 and String, nothing more. For importing it into the database I acutally need the Sql Server datatype equivalent. Unfortunately I cannot hardcode the datatype into the Table Creation Command since the order of the data is not the same for each query. E.g. First I receive Survey 1 data with the structure shown above. But maybe a few days later I need different data like
{"data":["4482359","2","3","1","12526","2015 Company X"]}
Deserialized the Json Data I have an object (RootObject) with a List(of String) called data. Where the first string is "4482359" the second is "2" the third is "3" and so on.
Public Class RootObject
Public Property data As List(Of String)
End Class
Public Class RootObjectDatatype
Private _rootObject As RootObject
Public Sub New(ByRef rootObject As RootObject)
For Each str As String In rootObject.data
If str > 0 And str < 50000 Then
jsonDatatype.Add("Int")
Else
jsonDatatype.Add("Varchar(" & str.Count & ")")
End If
Next
End Sub
Public Property jsonDatatype As List(Of String)
End Class
But this does not work yet.

JSON.serialize not returning valid json for nested objects

I need to serialize a nested structure of Salesforce objects as JSON but the result doesn't parse correctly.
public class Checklist_JSON {
// class to represent the structure of the checklist
// one opportunity
// one account
// one finance checklist (custom object)
// one/more integration checklists, (custom objects) each with
// one/more campaigns (custom objects)
public opportunity this_opp{get;set;}
public account this_acc{get;set;}
public finance_checklist__c this_fin{get;set;}
public map <integration_checklist__c, list<ph_campaign__c>> ints_cams{get;set;}
}
I then simply JSON.serialize(this_checklist_json);
The result can be parsed correctly for all objects except the integration_checklist__c - i.e. the keyset of the ints_cams map.
The other objects (account/oppty/etc.) each have a node 'attributes' containing the correctly formatted name/value pairs e.g.
{"attributes":{"type":"Account","url":"/services/data/v42.0/sobjects/Account/0015E00000WDO8ZQAX"},"Id":"0015E00000WDO8ZQAX",
etc.
but the integration_checklist__c doesn't have an 'attributes' node and has the fields represented like:
{"Integration_Checklist__c:{Id=a1E5E00000088lNUAQ, Name=INT-000339,
etc.
i.e. without quote marks around "ID":"a1E5E00000088lNUAQ"
Any ideas? Thanks in advance
Well... and what would you imagine the result should be? How would you represent "map whose keys are also objects" in a simple javascript object (because your map keys would be translated to field names during serialisation)?
Pick a primitive as the map key (Id, Decimal, String) or worst case - serialise the keys to strings, build new Map> and serialise that?
SF tries here, it calls "toString()" on your sobjects used keys, that's why you see 1 giant string. It looks identical to results of System.debug() call, doesn't it?
Thank you #eyescream for taking the time to respond.
The fundamental problem was that I shouldn't have been trying to represent the parent-child relationship as a map.
I've re-written based on represnting that relationship as a class:
public class Checklist_JSON {
// class to represent the structure of the checklist
// one opportunity
// one account
// one finance checklist
// one/more integration checklists, each with
// one/more campaigns
public opportunity this_opp{get;set;}
public account this_acc{get;set;}
public finance_checklist__c this_fin{get;set;}
public list<int_cams> these_ints_cams {get;set;}
}
public class int_cams {
//class to represent parent-children relationship int-list<cams>
public integration_checklist__c this_int {get;set;}
public list <ph_campaign__c> these_cams {get;set;}
}
serializing the result now produces my intended json output.

How do I parse this JSON using VB.net?

So, I'm working on a school project, and I'm trying to figure out the best way to deal with this data file that contains a pretty large amount of JSON objects. I know the basics of VB.net, basic event handling, etc.
I know the basics of designing Structures, and stuff like that, but I need to figure out how to parse and create a list of objects from a 5MB JSON file that contains entries such as the following:
{
"Air Elemental":{
"layout":"normal",
"name":"Air Elemental",
"manaCost":"{3}{U}{U}",
"cmc":5,
"colors":[
"Blue"
],
"type":"Creature — Elemental",
"types":[
"Creature"
],
"subtypes":[
"Elemental"
],
"text":"Flying",
"power":"4",
"toughness":"4",
"imageName":"air elemental"
},
"Ancestral Recall":{
"layout":"normal",
"name":"Ancestral Recall",
"manaCost":"{U}",
"cmc":1,
"colors":[
"Blue"
],
"type":"Instant",
"types":[
"Instant"
],
"text":"Target player draws three cards.",
"imageName":"ancestral recall"
},
"Animate Artifact":{
"layout":"normal",
"name":"Animate Artifact",
"manaCost":"{3}{U}",
"cmc":4,
"colors":[
"Blue"
],
"type":"Enchantment — Aura",
"types":[
"Enchantment"
],
"subtypes":[
"Aura"
],
"text":"Enchant artifact\nAs long as enchanted artifact isn't a creature, it's an artifact creature with power and toughness each equal to its converted mana cost.",
"imageName":"animate artifact"
}
}
If anyone could be of assistance, or just sort of point me in the right direction, I'd really appreciate it. I think the part that's throwing me off the most is that each card name is a key in itself, and all of the card's data is the value associated with the name "key"...
In this case it hardly matters how many there are because they are all structured the same way:
Public Class Spell
Public Property layout As String
Public Property name As String
Public Property manaCost As String
Public Property cmc As Integer
Public Property colors As String()
Public Property type As String
Public Property types As String()
Public Property subtypes As String()
Public Property text As String
Public Property power As String
Public Property toughness As String
Public Property imageName As String
End Class
I have no idea what the data represents, it looks like some fantasy game. When deserialized (I used Newtonsoft), you will end up with a Dictionary of spells with the key being "Air Elemental" and "Animate Artifact" etc. It takes but one line of code:
Dim jstr As String = from whereever
Dim mySpells = JsonConvert.DeserializeObject(Of Dictionary(Of String, Spell))(jstr)
Using the NET JavaScriptSerializer is about the same:
Dim jss As New JavaScriptSerializer
Dim myspells = jss.DeserializeObject(jstr)
You can use http://jsonutils.com/, or even Paste Special in VS, to help parse what the structures (classes, really) need to look like. However, it pays to use your brain and look at them. A robot will create 3 classes for that JSON and another class container to hold them. If there were 100 of them it would be needlessly long.
Since each item is identical and the JSON one class can be used for each. Since the JSON is formatted to accommodate, a standard NET dictionary works fine.
There is a wonderful feature in VS 2013 called "Paste as JSON" under the Edit menu, so copy your JSON string and choose this feature.
Be aware that there is a small bug that I reported to MS in the way that it declares arrays. The text it gives you will be
Public Property x() as DataType
however it needs to be changed to
Public Property x as DataType()
in order to be correctly declared as an array.

vb.net json + deserialise list within a list

I am using json.net to deserialise a json string into a classed object for use in a vb.net console application. I have started to set up classes for each of these fields but I am a bit confused as to how I can set up the sta class as it appears to be an array of a list?
I would appreciate any help you can provide, the plan is to use the Json.JsonConvert.DeserializeObject to deserialize the string into the class. I will error handle as some strings don't have any strokes, just the time.
{"time":1423625141,"id":35609390,"strokes":[{"time":1423625137180,"lat":-34.4798
08,"lon":147.249959,"alt":0,"cur":0,"dev":6553,"inv":0,"sta":[9,[812,849,919,118
5,874,1248,984,1276,875]],"id":35609386},{"time":1423625137250,"lat":-34.542924,
"lon":147.299573,"alt":0,"cur":0,"dev":7505,"inv":0,"sta":[9,[812,849,877,919,11
85,874,1248,984,1276,875]],"id":35609388},{"time":1423625137552,"lat":-34.514597
,"lon":147.284943,"alt":0,"cur":0,"dev":6894,"inv":0,"sta":[7,[849,919,1185,1248
,984,1276,1016,875]],"id":35609389}]}
My Class is below:
Class Data
Public time As Integer
Public id As Integer
Public strokes As List(Of Strokes)
End Class
Class Strokes
Public time As Integer
Public lat As Decimal
Public lon As Decimal
Public alt As Integer
Public cur As Integer
Public dev As Integer
Public sta As New sta
End Class
Class sta
Public sta As List(Of Integer)
End Class
Even though you have a complex object sent via JSON the DefaultModelBinder should pick it up and map it to your Model. There are a couple things you need to make sure of though.
The first is how you send your JSON. The content-type should be explicity set to "application/json" and if using JQuery you need to use the $ajax method (not $post) and be sure to stringify to format the data properly). I also use Fiddler to catch the JSON and run it through an online validator to be sure it is passing correctly formatted.
$.ajax( {
type: "POST",
url: /MyJsonActionController',
contentType: 'application/json; charset=utf-8',
data: Json.stringify(MyFormData)
}
Secondly, Your action controller should simply state the model to be mapped to in the constructor Ex:
Public Function MyJsonActionController(ByVal d as Data) JsonResult
'ModelBinder should do all of the work and then you can use the incoming model to do what you'd like
SaveToDatabase(d)
return Json(true)
End Function
Also be sure to name the form fields according to the Model value names. That should do it.
If you run into any trouble, this is a great article explaining very clearly how ModelBinding works. You will see that according to this article the ModelBinder will make a first pass to read all of the primitive types to map the model and if there are more complex types it will recursively make another pass and pick those up and map them. The DefaultModelBinder can actually handle complex/nested model mapping out of the box if the JSON is presented correctly.
https://msdn.microsoft.com/en-us/magazine/hh781022.aspx