Get specific Json field with NewtonSoft - json

Im using newtonsoft, and I need to get two specific fields on a Json response:
{
"id": "1233323",
"quoteOptions": [{
"copay": "20%",
"deductables": [{
"deductable": "$250",
"quoteOptions": [{
"pricingAndLimits": {
"reimbursement": "80%",
"copay": "20%",
"deductable": "$250",
"limit": "$4,000",
"annualPremium": "$413.00",
"monthlyPremium": "$34.00"
}
}]
}]
}]
}
I need to do this on a legacy intranet (VB.NET). I specifically need to get the monthlyPremium field and the id field.
I tried
Dim json As String = Result
Dim ser As JObject = JObject.Parse(json)
Dim data As List(Of JToken) = ser.Children().ToList
Dim output As String = ""
Dim Premium As String = ser("quoteOptions")("deductables")("quoteOptions")("pricingAndLimits")("monthlyPremium")
But I get an error at "deductables" (doesn't exist).
Thanks :)

I've made it work like this:
Money = ser("quoteOptions")(0)("deductables")(0)("quoteOptions")(0)("pricingAndLimits")("monthlyPremium")
Thanks CrlueD

Related

How to add JObjects to a JArray when serializing a DataTable to JSON using custom formatting rules?

When attempting to serialize a DataTable to JSON using a custom format, I have some trouble adding JObjects (representing a row) to my JArray (representing the table).
So what I hope to make the table look like is something like this:
[
"Orderline" : {"Item": "Table", "Quantity": "5", "Amount": "50$"},
"Orderline" : {"Item": "Chair", "Quantity": "20", "Amount": "30$"},
"Orderline" : {"Item": "Couch", "Quantity": "2", "Amount": "500$"}
]
I have tried using the Add method to the JArray but I cannot seem to get it to work properly.
At the beginning I have set the JArray to new JArray, so that it is in memory and then I will go along and add the JObjects to it one at a time.
I can see that the add method takes two arguments (Item as JToken and content as object) which makes me a little confused because I do not see anyone else addressing both arguments in other code snippets I have seen online.
JArray is a instance of class Newtonsoft.Json.Linq.JArray.
Desired JObject output:
{
"Orderlines": {
"Item": "Table",
"Quantity": "5",
"Amount": "50"
}
}
Draft code:
Dim JsonObejct as JObject
Dim MyArray as Jarray
Dim Table as datatable
Set MyArray = new JArray
for each row in table
JsonObject = Jobject.FromObject(
New With {
Key.Orderlines = New With{
key.Item = row("Item").Tostring,
key.Quantity = row("Quantity").tostring,
key.Amount = row("Amount").tostring
}
}
)
Myarray.add(JsonObject)
Next row
I work in UiPath Studio and do not have the code in the same place its separated in multiple activities, so please don't get caught in wrongly defined details in the code, everything works until the add to jarray part.
I use Vb .net in UiPath Studio so I would appreciate a solution on how to add the JObects to my JArray in vb .net.
If you simply need to fix your compilation, the following compiles successfully and generates the required JSON structure:
Public Module DataTableJsonExtensions
Public Function ToSpecificOrderlines(ByVal table As DataTable) As JArray
Dim MyArray as JArray = New JArray
For Each row As DataRow In table.Rows
' Possibly you need to use CultureInfo.InvariantCulture in your ToString calls
Dim JsonObject As JObject = JObject.FromObject(
New With {
Key.Orderlines = New With{
key.Item = row("Item").ToString,
key.Quantity = row("Quantity").ToString,
key.Amount = row("Amount").ToString
}
}
)
MyArray.add(JsonObject)
Next row
Return MyArray
End Function
End Module
And then do
Dim myArray as JArray = DataTableJsonExtensions.ToSpecificOrderlines(table)
Demo fiddle #1 here.
However, it seems preferable to generalize the code to serialize any set of DataTable columns by name, with an optional specified format:
Public Module DataTableJsonExtensions
' Serialize all the columns of the table to an Orderlines array
Public Function ToOrderlines(ByVal table As DataTable) As JArray
Return ToOrderlines(table, table.Columns.Cast(Of DataColumn).Select(Function(c) c.ColumnName).ToArray())
End Function
' Serialize the selected columns of the table to an Orderlines array with the specified culture and formats (if any)
Public Function ToOrderlines(ByVal table As DataTable, ByVal columns() As String, Optional ByVal culture As CultureInfo = Nothing, Optional ByVal formats As IDictionary(Of String, String) = Nothing) As JArray
culture = If (IsNothing(culture), CultureInfo.InvariantCulture, culture)
Dim array as JArray = New JArray
For Each row As DataRow In table.Rows
Dim obj As JObject = new JObject (
new JProperty("Orderlines",
New JObject(columns.Select(Function(c) New JProperty(c, String.Format(culture, If(Not IsNothing(formats) AndAlso formats.ContainsKey(c), formats(c), "{0}"), row(c)))))
)
)
array.add(obj)
Next row
Return array
End Function
End Module
Then, to get the JSON shown at the top of your question, with the $ appended to the "Amount" property's value, do:
Dim formats = New Dictionary(Of String, String) From {{"Amount", "{0}$"}}
Dim myArray as JArray = DataTableJsonExtensions.ToOrderlines(table, {"Item", "Quantity", "Amount"}, Nothing, formats)
If you don't need the formatting after all, you call it as follows:
Dim myArray as JArray = DataTableJsonExtensions.ToOrderlines(table, {"Item", "Quantity", "Amount"})
Notes:
You can use DataTableJsonExtensions.ToOrderlines(table) to serialize all columns of the table to an Orderlines array.
In general serialization should always be performed using the invariant culture so that JSON serialized in one locale (say, the United States) can be deserialized in another locale (say, Europe) which uses a different decimal separator or DateTime format. ToString(), however, formats its values using the current culture. Thus I provided the option for you to specify a formatting culture in case you really want to serialize in CultureInfo.CurrentCulture. Passing Nothing for the culture results in using the invariant culture.
In the JSON shown in the top of your question you append a $ to the Amount column, so I provided an optional dictionary of formats in case you need to add that when serializing.
Demo fiddle #2 here.

JSON to DataTable net with varing roots

This is my first dealing with JSON and unfortunately I have to do it in VB.Net, company policy. So I have searched high and low and tried a lot of examples even converted some of the C# code to VB.Net but I can't seem to find a complete solution.
I receive a JSON string like this:
{
"65080007":{
"partNo":"ATD000007",
"description":"Swingarm Hat Platform",
"quantity":4,
"assemblyseq":""
},
"65080143":{
"partNo":"ATD000143",
"description":"ASY Gas Spring Bracket",
"quantity":2,
"assemblyseq":""
},
"65080071":{
"partNo":"ATD000071",
"description":"TT Gas Spring",
"quantity":2,
"assemblyseq":""
},
"65080147":{
"partNo":"ATD000147",
"description":"ASY Lateral Hinge",
"quantity":8,
"assemblyseq":""
},
"65085181":{
"partNo":"RD0181",
"description":"ASY KIT Bolt, Carriage, 0.375 in x 16, 1.5 in (x45) & Nut, Flange, 0.375 in x 16 (x45)",
"quantity":1,
"assemblyseq":""
},
"65080796":{
"partNo":"ATD000796",
"description":"Decal, TT Equipped, Rectangular, 5 in x 10 in",
"quantity":1,
"assemblyseq":""
},
"65080797":{
"partNo":"ATD000797",
"description":"Decal, TT Open/Close, Triangular, 12 in x 8 in",
"quantity":1,
"assemblyseq":""
},
"65080745":{
"partNo":"ATD000745",
"description":"",
"quantity":1,
"assemblyseq":""
}
}
What I need to do bind or assign this data to a DataGridView.DataSource.
I've seen some examples but I can't set it as a DataSource.
I've tried this example:
Sub Main()
Dim json_result = GetJson()
Dim table = JsonConvert.DeserializeAnonymousType(json_result, (DataTable))
Dim newJString = Newtonsoft.Json.JsonConvert.SerializeObject(table, Newtonsoft.Json.Formatting.Indented)
Console.WriteLine("Re-serialized JSON: ")
Console.WriteLine(newJString)
Console.WriteLine("")
End Sub
Public Function GetJson() As String
Dim json_result As String = <![CDATA[
' I used the above json string
Return json_result
End Function
I have made my JSON classes to deserialise the JSON and tried JsonConvert.Deserialize keep getting an error it epected a array and found an object.
Public Class Jobs
'<JsonProperty("partno")>
Public Property PartNo As String
' <JsonProperty("description")>
Public Property Description As String
'<JsonProperty("quantity")>
Public Property Quantity As String
'<JsonProperty("assemblyseq")>
Public Property Assemblyseq As String
End Class
The issue I think is the root properties "65080797" these numbers will not be the same every time we get the JSON back from NetSuite.
So I tried to:
Dim obj = JsonConvert.DeserializeObject(Of Jobs)(result)
Console.WriteLine(obj.PartNo) it comes out PartNo = nothing
So I've tried this:
Dim resultA = JsonUtil.Deserialize(Of Jobs)(result, ignoreRoot:=True)
Module JsonUtil
Function Deserialize(Of T As Class)(ByVal json As String, ByVal ignoreRoot As Boolean) As T
Return If(ignoreRoot, JObject.Parse(json)?.Properties()?.First()?.Value?.ToObject(Of T)(), JObject.Parse(json)?.ToObject(Of T)())
End Function
End Module
This gives me the first group:
ATD000007
Swingarm Hat Platform
4
The assembly number was blank.
I'm open for any suggestions on how I can get the above JSON into a data table or DataGridView or how to make a list without the root "65080797" this number will be unique with every response.
The people that designed this response string refuses to remove the root properties.
Thank you for taking the time to read this mess.
All comments/suggestions are appreciated.
Yes, Json array looks like [something] instead of {somthing}, you could convert it to array if you want but you can also do it in different ways and even without any external library, you could create a datatable then bind it to datagridview or you could add data directly to datagridview.
Anyway, I made a datatable for you.
Imports System.Web.Script.Serialization 'for reading of JSON (+add the reference to System.Web.Extensions library)
Dim JSONC = New JavaScriptSerializer().Deserialize(Of Dictionary(Of String, Dictionary(Of String, String)))(JSON) 'you could do it in different ways too
Dim NewDT As New DataTable
'Create Columns
For Each key In JSONC.First.Value.Keys
'"65080007" <first
'{ "partNo":"ATD000007", "description":"Swingarm Hat Platform", "quantity":4, "assemblyseq":"" } <first.value
' "partNo" <first.value.key(s) :"ATD000007" <first.value.value(s)
NewDT.Columns.Add(key)
Next
'Add Rows
For Each item In JSONC
NewDT.Rows.Add(item.Value.Values.ToArray)
Next
DataGridView1.DataSource = NewDT
If you have unusually structured JSON like that, your best bet is probably to resort to using raw JObject and JToken handling instead of trying to get JSON.NET to deserialize into structured data automatically.
Create a method that will convert an individual JToken into the Job class you described in your question. I've added a Key property to identify those unique keys in the JSON that were problematic for you; if you don't need these, just remove the .Key bit from the example below.
Public Function CreateJob(data As JToken)
Return New Job With
{
.Key = data.Path,
.PartNo = data("partNo"),
.Description = data("description"),
.Quantity = data("quantity"),
.Assemblyseq = data("assemblyseq")
}
End Function
Once you have Job objects being created, you can walk the entire structure and turn it into an array of jobs with the sample code below.
Dim result As JObject = JsonConvert.DeserializeObject(json)
Dim jobs As Job() = result.Values().Select(Of Job)(AddressOf CreateJob).ToArray()
Once you have an array of Job objects, binding to a DataSource should be trivial.

Retrieve index of JSON array from

I have a standard JSON array returned to me which I have deserialized with JsonConvert, below being a simplified representative of my situation:
[
{
"name": "John",
"age": "21",
},
{
"name": "Sally",
"age": "18",
},
{
"name": "Harry",
"age": "25",
}
]
...
Public Class myExample
Public Property name as String
Public Property age as Integer
End Class
...
Dim serverResponse as string = reader.ReadToEnd()
Dim jsonResult = JsonConvert.DeserializeObject(Of List(Of myExample))(serverResponse)
I can easily retrieve the values of name or age given the item index, e.g.,
Dim someValue = jsonResult.Item(1).name ' returns Sally
Dim someOther = jsonResult.Item(1).age ' returns 18
Yet I wish to return the index (integer) of the array given the name: i.e., how might I search for Sally and retrieve the Item index integer (in this case 1), or in the case of John, return 0? I have not been able to achieve this with jsonResult.IndexOf(), or jsonResult.FindIndex() and searches have not been fruitful.
I have an extensive JSON and wish to loop through names on a dataGridViewer column, returning the ages of all names to another column.
Thanks for helping a novice out!
Since deserialization in this manner results in List(of T), the index to the above example can be found through, for example:
jsonResult.FindIndex((Function(s) s.name.Equals(someNameToCheck))))
or any other method of finding an item in a list.

Get Json value with Hierarchies and Put on in a Variable

I'm trying to get the number of subscribers from a channel using the Youtube API. But this api contains some levels of hierarchy before reaching the value and using the code I know can only get up to 2 levels. How do I get this value and put it in a variable and then put it in a label, my code is not working.
NOTE: I'm using Newtonsoft.Json
API Link
https://www.googleapis.com/youtube/v3/channels?part=statistics&id=UCuxfOdbKQy0tgGXcm9sjHiw&fields=items(statistics(subscriberCount))&key=AIzaSyA1n4M-fo2Y5NHUj0RsvXEAis3H6_lIjRg
Json
{
"items": [
{
"statistics": {
"subscriberCount": "7484439"
}
}
]
}
Code
Dim ChannelID As String = "UCuxfOdbKQy0tgGXcm9sjHiw"
Dim Subs As String
Dim json = New IO.StreamReader(DirectCast(DirectCast(Net.WebRequest.Create("https://www.googleapis.com/youtube/v3/channels?part=statistics&id=" & ChannelID & "&fields=items(statistics(subscriberCount))&key=AIzaSyA1n4M-fo2Y5NHUj0RsvXEAis3H6_lIjRg"), Net.HttpWebRequest).GetResponse, Net.HttpWebResponse).GetResponseStream)
Dim rq As Newtonsoft.Json.Linq.JToken = Newtonsoft.Json.Linq.JObject.Parse(json.ReadToEnd)
Subs = $"{rq.SelectToken("items")("statistics")("subscriberCount")}"
Label1.Text = Subs
This
Subs = $"{rq.SelectToken("items")("statistics")("subscriberCount")}"
should be
Subs = $"{rq.SelectToken("items")(0)("statistics")("subscriberCount")}"

Collect All appID's from a JSON file

My question is about a JSON file, of which I'm getting errors when putting certain values in a text component.
{
"response": {
"game_count": 4,
"games": [
{
"appid": 10,
"playtime_forever": 0
},
{
"appid": 20,
"playtime_forever": 0
},
{
"appid": 30,
"playtime_forever": 0
},
{
"appid": 40,
"playtime_forever": 0
}
]
}
}
I'm trying to get the values "10,20,30,40" from "appid" in a RichTextBox, one below the other. For this, I am using this code:
JsonString = file
Dim jsonObject As JObject = JObject.Parse(JsonString)
Dim JsonArray As JArray = JArray.Parse(jsonObject.SelectToken("games").ToString)
For Each item As JObject In JsonArray
RichTextBox2.Text = item.SelectToken("appid").ToString
Next
But I'm getting the following error in line 4 of the above code:
Object reference not set to an instance of an object
Is there a way to fix this? I believe my code is right. I'm using the NewtonSoft library.
You can use SelectTokens("..appid") to recursively descent the JSON token hierarchy and find values of properties named "appid", where ".." is the JSONPath recursive descent operator:
Dim jsonObject As JToken = JToken.Parse(JsonString)
Dim appids = jsonObject _
.SelectTokens("..appid") _
.Select(Function(t) CType(t, Long)) _
.ToList()
After finding all "appid" values I cast then to Long using an explicit conversion cast. You could cast to Int If you are certain that all appid values will be less than Int.MaxValue. Or you could cast then to String if you're not interested in the numeric values.
Working .Net fiddle.