JSON.net combine 2 list(Of JObject) together - json

Heyy all I am trying to combine 2 JObject lists. I have 2 list(Of JObject) named masterJsonList.Add(jsonWriter.Token) and masterJsonListNA.Add(jsonWriter.Token).
I have not found anything when searching Google that shows me how to combine JObects masterJsonListNA to masterJsonList.
When I try:
masterJsonList.Add(masterJsonListNA) '<-- error here
Dim finalJson As String = JsonConvert.SerializeObject(masterJsonList, Formatting.Indented)
It gives an error of:
Error BC30311 Value of type 'List(Of JObject)' cannot be converted to 'JObject'.
I have even tried the following with no luck as well:
masterJsonList.Concat(masterJsonListNA)
Dim finalJson As String = JsonConvert.SerializeObject(masterJsonList, Formatting.Indented)
Although there is no error using Concat, I only get the masterJsonList values in finalJson and not both masterJsonList & masterJsonListNA.
masterJsonList.Union(masterJsonListNA)
Dim finalJson As String = JsonConvert.SerializeObject(masterJsonList, Formatting.Indented)
And again using Union there is no error, but I also again only get the masterJsonList values in finalJson and not both masterJsonList & masterJsonListNA.
I know it works if I do this:
Dim combinedJsons As Object = masterJsonList.Concat(masterJsonListNA)
Dim finalJson As String = JsonConvert.SerializeObject(combinedJsons, Formatting.Indented)
But I would like to know if that's the correct way of doing this?

Yes. Your final guess is correct. The extension methods Concat, Union, etc. don't operate on the object they're invoked on. Instead they return new object containing the result of the operation. You actually don't need to us As clause for the combinedList - let the compiler to infer it, like so:
Dim combinedJsons = masterJsonList.Concat(masterJsonListNA)
But if you don't need the combinedJsons for anything else you can Concat the lists in place of the first parameter to SerializeObject:
Dim finalJson = JsonConvert.SerializeObject(masterJsonList.Concat(masterJsonListNA), Formatting.Indented)
On the other hand, the List<T>.Add() method do work on the instance it is invoked on, BUT it adds objects of type T, not whole lists of type T.

Related

JSON Deserializing list of lists

I have a problem deserializing the following JSON string:
{"error":null,"id":1234,"result":[[["config.param1","111"],["config.param2","1222"]],"Config System",1234]}
My structure is:
Public Structure stuConResponse
Dim [Error] As String
Dim ID As String
Dim Result As List(Of stuSubResults)
End Structure
Public Structure stuSubResults
Public Property X1 As List(Of List(Of String))
Public Property X2 As String
Public Property X3 As String
End Structure
And my code is:
Dim JSonSettings As New Newtonsoft.Json.JsonSerializerSettings
JSonSettings.CheckAdditionalContent = True
JSonSettings.DateParseHandling = Newtonsoft.Json.DateParseHandling.DateTime
JSonSettings.DefaultValueHandling = Newtonsoft.Json.DefaultValueHandling.Ignore
JSonSettings.FloatFormatHandling = Newtonsoft.Json.FloatFormatHandling.DefaultValue
JSonSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore
Dim HeloResponse As Structures.stuConResponse = Newtonsoft.Json.JsonConvert.DeserializeObject(Of Structures.stuConResponse)(ReceivedData, JSonSettings)
I tried making "Results" the following:
1) A tuple of (list of (list of (string), string, string))
2) A list of (list of (string))
3) Other lists and tuples combined
For the life of me, I can't deserialise the "result" object whatsoever.
I have no problems reading the error and ID, but when Result comes in, I get the error that JSON can't do it.
I don't also mind if "result" can go into a string un-deserialised where I can do some manual logic, but that also don't work as JSON is trying to be too cleaver.
In other words, the problem is getting JSON to read "[[[X1,Y1],[X2,Y2],X3,X4]", notice that it's a list/array and that it does not have any Key-names which is where the problem is (I think).
It would be great to get your thoughts on this one.
Thanks
Dim JSONC = New JavaScriptSerializer().DeserializeObject(yourjson)
Debug.Print(JSONC("result")(0)(0)(0)) 'get result collection, then first element, then first object then first element of object
You decide what you want to do with the object.
You can convert ii to dictionary then get stuff with ("key") but if the data stays the same I see no point.
Finally, I solved it!, I had no idea that you can use IDICTIONARY to read the whole thing and then break it down into ILISTs...
For anyone who is having the same problem, here is the solution:
1) Code:
Dim I As Integer
Dim ConPolConfig As Structures.stuConPolSubscribeResponse = Nothing
Dim dicItems As IDictionary = Newtonsoft.Json.JsonConvert.DeserializeObject(Of IDictionary)(ReceivedData, JSonSettings)
ConPolConfig.ID = dicItems("id")
ConPolConfig.Error = dicItems("error")
If Not dicItems("result") Is Nothing Then
ConPolConfig.ConfigItems = New List(Of Dictionary(Of String, String))
Dim ConfigProperties As IList = dicItems("result")(0)
Dim ConfSysReader As String = dicItems("result")(1)
Dim Token As Integer = dicItems("result")(2)
Dim ParamKey As String
Dim ParamVal As String
Dim Dic As New Dictionary(Of String, String)
For I = 0 To ConfigProperties.Count - 1
ParamKey = ConfigProperties(I)(0)
ParamVal = ConfigProperties(I)(1)
Dic.Add(ParamKey, ParamVal)
ConPolConfig.ConfigItems.Add(Dic)
Next
End If
2) Structures:
Public Structure stuConPolSubscribeResponse
Dim [Error] As String
Dim ID As String
Dim ConfigItems As List(Of Dictionary(Of String, String))
End Structure
This works and does exactly what I am looking for as per my initial question. i.e. reading a list or lists where the master list has an additional 2 different elements (a string and an integer). the iDictionary would read the whole thing without any errors and then you could iterate it using an ILIST...
Don't ask me why the source JSON string is written in such a way... but now this works to read it...
... I need a coffee ...

JSON Response not reporting properly

I'm using the newtonsoft.dll to deal qwith the proper JSON responses from a site, i have come in to an issue, the delete code:
Dim delPro As String
Dim resPro As String
Dim sB As New StringBuilder()
For Each row As DataGridViewRow In dataGridProjects.Rows
If (row.Cells(4).Value IsNot Nothing) Then
' JSON
delPro = srFunctions.postURL("http://www.ste.com/ajax_task.php?act=add&task=projectDelete", "project_ids=" + row.Cells(0).Value.ToString(), varCookieJar)
resPro = srFunctions.postURL("http://www.ste.com/ajax_task.php?act=status&task=projectDelete", "", varCookieJar)
' purely for debugging
sB.Append("1: " + delPro)
sB.Append(Environment.NewLine + "----------------------------------------------------------------" + Environment.NewLine)
sB.Append("2: " + resPro)
sB.Append(Environment.NewLine + "----------------------------------------------------------------" + Environment.NewLine)
' responses
Dim tempPost = New With {Key .message = "", Key .error = 0, Key .done = False, Key .jsdata = ""}
Dim obj = JsonConvert.DeserializeAnonymousType(resPro, tempPost)
Dim com As String = obj.message
Dim obj2 = JsonConvert.DeserializeObject(Of saperJsonObject)(resPro)
If CBool((CStr(obj2.done))) Then
dataGridProjects.Rows.Remove(row)
Me.returnMessage("Project has been deleted!")
Else
dataGridProjects.Rows.Remove(row)
Me.returnMessage("Site returned an unknown response! (The action still most likely was executed)" & vbCrLf & vbCrLf & "Returned response was: " & (CStr(obj2.done)))
End If
End If
Next
The site returns 2 different success responses, this one:
{"error":0,"done":0,"message":"\u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0437\u0430\u0434\u0430\u043d\u0438\u0435: 0/1","data":[true,true,0,1]}
Has true,true,0,1 at the end which is a success (the action is still completed) the other one looks like:
{"error":0,"done":1}
or similar, the done:1 also denotes a success, i'm not sure how to look for both success values, i know i need to edit here : If CBool((CStr(obj2.done))) Then but i'm not sure how to go about it.
any help would be great guys!
cheers
Graham
Without a class structure, DeserializeObject is problematic (resPro at least is defined as String). It works, and you can get the done property, but requires Option Strict Off, which is not usually a good idea.
You can also just parse the response if that status is all you need to know.
Public Class Russianobject
<JsonProperty("error")>
Public Property JError As Integer
Public Property done As Boolean
Public Property message As String
Public Property data As Object() ' object array
End Class
This is what the longer message looks like (you didnt post what your saperJsonObject looked like) . I had to change the Error property because it is a reserved word in VB. Also, I changed done from Int32 to Boolean. The last item, data is just an array of objects, and it is not clear which element you need.
Even though the short response does not have all these elements, you can use the same class, message will be empty and datawill be Nothing, so you will have to check!
Dim jstr = from whereever russian objects come from
Dim jobj = JsonConvert.DeserializeObject(Of Russianobject)(jstr)
If jobj.data IsNot Nothing Then
Console.WriteLine("0: {0}, 1: {1}, 2:{2}, 3: {2}", jobj.data(0),
jobj.data(1), jobj.data(2), jobj.data(3))
Else
Console.WriteLine(jobj.done)
End If
This should work whether you get a long or short response. To simply parse it, you do not need a class:
' using the short one:
jstr =...from whereever
jp = JObject.Parse(jstr)
Dim jd = jp.SelectToken("data")
If jd IsNot Nothing Then
Console.WriteLine("0: {0}, 1: {1}, 2:{2}, 3: {2}", jd(0), jd(1), jd(2), jd(3))
Else
Console.WriteLine("done = " & Convert.ToBoolean(jp("done")))
End If
Note that in this case, the property name is used like a key.
Output:
0: True, 1: True, 2:0, 3: 0
done = 1
The long response results in the first, the short results in the second. Whether you use a class and deserialize to an object or simply parse it, you will have to check the data element for Nothing (as shown) since it wont exist in the short response.

Query to parse a field and display it

I have a table with values
Errors:
X_11;SR_4;D_11;SR_2
SR_4;T_22
E_18; E_28; SR_3;
E_28; SR_3;
SR_2;SR_4
I need to put in a query to parse the values so that anything with SR comes up so I do like "*SR*" but in the output I need to display only this:
Errors:
SR_4;SR_2
SR_4
SR_3
SR_3
SR_2;SR_4
I would like this in query with many fields other than this one ... instead of VBA. I am using MS Access 2010, I am guessing some type of parsing with each field being separated with ";" that will only capture SR ones?
I think regular expressions might be a way to go.
In VBA, you need to enable the reference to "Microsoft VBScript Regular Expressions 5.5". This question and its accepted answer has a detailed descrpition on what are Regular Expressions and how to enable them in your project (it's for Excel, but for Access is the same route).
Once you have the reference enabled, this little function will give you a "clean" string:
Public Function filterString(str As String)
Dim re As RegExp, obj As Object, x As Variant, first As Boolean
Set re = New RegExp
With re
.Global = True
.IgnoreCase = True
.MultiLine = False
.Pattern = "SR_[0-9]" ' This will match the string "SR_"
' followed by a digit
End With
filterString = ""
first = True
If re.Test(str) Then
Set obj = re.Execute(str)
For Each x In obj
If first Then
first = False
Else
filterString = filterString & ";"
End If
filterString = filterString & x
Next x
End If
End Function
If you test it you'll see that the result is:
filterString("X_11;SR_4;D_11;SR_2")
SR_4;SR_2
which is the result you want.
Now, a simple select query will give you what you need:
select filterString([Errors]) as err
from [yourTable]
where [yourTable].[Errors] like '*sr*'
Hope this helps
I think you can get what you need by splitting your input string into an array and then using the Filter function to create a second array which includes only the SR_ matches from the first array. Finally Join the second array to produce your output string which contains the matches.
Public Function filterString(ByVal pInput As String) As String
Dim array1() As String
Dim array2() As String
array1 = Split(Replace(pInput, " ", vbNullString), ";")
array2 = Filter(array1, "SR_")
filterString = Join(array2, ";")
End Function
Compared to a regular expression approach, this function is more concise. I find the logic simpler. And it does not require setting a reference.
Notice also it will accommodate SR codes which include more than a single digit (in case that eventually becomes a requirement). For example:
? filterString("X_11;SR_4;D_11;SR_234")
SR_4;SR_234
You could use that function in a query in the same way #Barranka suggested:
SELECT filterString(y.Errors) AS sr_codes
FROM [yourTable] AS y
WHERE y.Errors Like '*sr*';

How to convert a string list into a single list in vb.net?

I am using VS2013 and .NET FrameWork 4.0.
I am building an app that reads a json file and acts upon it.
I have successfully written the code to deserialize the json file and I have a list(of String) which I would like to join in a single string.
This is my code:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim g As GameData = Nothing
Using fileStream = New System.IO.FileStream("C:\Users\KE-KL\Desktop\Levels\level_0017.json", System.IO.FileMode.Open)
fileStream.Position = 0
Dim ser = New System.Runtime.Serialization.Json.DataContractJsonSerializer(GetType(GameData))
g = DirectCast(ser.ReadObject(fileStream), GameData)
End Using
Dim final As String
final = String.Join(",", g.board.tiles.ToArray)
End Sub
But this line:final = String.Join(",", g.board.tiles.ToArray) creates this error:
Error 1 Overload resolution failed because no accessible 'Join' is most specific for these arguments:
'Public Shared Function Join(Of System.Collections.Generic.List(Of String))(separator As String, values As System.Collections.Generic.IEnumerable(Of System.Collections.Generic.List(Of String))) As String': Not most specific.
'Public Shared Function Join(separator As String, ParamArray values() As Object) As String': Not most specific
Any idea how to fix this?
If you need more details, please do ask.
Thank you in advance
As your error message said: you trying to pass array of List(Of String) to array of Objects
Try as #Michinarius advised use Aggregate method:
final = g.board.tiles.Aggregate(Of StringBuilder)(New StringBuilder(), _
Function(temp, val)
temp.Append(String.Join(",", val))
Return temp
End Function).ToString()
Your problem is that a List(Of List(Of String)) will convert to a multi-dimensional array with the ToArray() call, which String.Join does not handle. Since you have a list of lists, you could do String.Join(",", g.board.titles(0)) and that should work.
Also note that I didn't need the ToArray() call because one of the overrides for join takes an IEnumerable(Of T), which List(Of T) implements.
I think this is because you are trying to join a String (",") and an array (g.board.tiles.ToArray). The Join method doesn't accept String and Array arguments. Choose one or the other, and remember to include an index (or multiple indices for multidimensional arrays) when dealing with specific parts of arrays.

Newtonsoft json exception

I am currently making a program that parses the Urban Dictionary API but I cannot get it to return the selected definition.
This is my current code fore retrieving and parsing the data:
Dim sourceString As String = New System.Net.WebClient().DownloadString("http://api.urbandictionary.com/v0/define?term=" & strRet)
rtxtDefinition.Text = sourceString
Dim jResults As JArray = JArray.Parse(sourceString)
Dim results As List(Of JToken) = jResults.Children().ToList()
For Each item As JProperty In results
item.CreateReader()
MsgBox(item.Value("definition"))
Next
note that strRet is the users input
this is an example of the urban dictionary API structure: http://pastebin.com/11Z5uVRN
The current code does not have support to find the (n)th definition only because I first need to get it to return a definition.
So obviously I am doing something wrong because of the error: Newtonsoft.Json.JsonReaderException but I am not sure.
Any help would be amazing. Thanks!
EDIT:
Root of json string you're dealing with is not an array but single object. Therefore, you can parse it to JObject instead of JArray, for example :
Dim jobj As JObject = JObject.Parse(sourceString);
Dim arr As JArray = jobj("list");
For Each(var item in arr.Children(Of JObject)())
MsgBox(item("definition").ToString());
Next