Using Jtoken.FromObject results in double curly brackets which results in a JSON parse error, here is a simple example
object jtokenObject = new { Data = JToken.FromObject(new {Name="some name"}) };
Console.WriteLine(jtokenObject);
//{ Data = {{ "Name": "some name"}} }
JToken anotherToken = JToken.FromObject(jtokenObject);
Console.WriteLine(anotherToken);
//{{ "Data": { "Name": "some name" }}}
Does anyone know about a quick fix that does not require converting to string and removing or serializing / deserializing?
Related
I get the following: How to make it as a valid JSON?
{{
"id": "123",
"name": "Kaizen",
"living": {
"city": "Sydney",
"state": "NSW"
},
"Country": {
"name": "Australia",
"region": "APAC"
}
}}
It looks like a valid JSON except for the opening and closing bracket.
You can simply cut it out:
string jsonString = yourServerClient.GetData();
jsonString = jsonString.Trim();
jsonString = jsonString.Substring(1, jsonString.Length - 2);
var jsonObj = JsonConvert.DeserializeObject(jsonString);
However, I would recommend you to refuse using any incorrect or invalid data sources - it is the road to hell.
You can never expect what they do next, and you definitely do not want to spend much of your time every time they change their service, and rewrite (and worsen) your code such that it now supports their incorrect format.
I'm having a string that could look like this:
{
"acl_gent": {
"cluster": [],
"indices": [{
"names": ["am*"],
"privileges": ["read", "view_index_metadata"],
"query": "{\"match\": {\"ACL\": \"acl_gent\"}}"
}],
"run_as": []
},
"acl_luik": {
"cluster": [],
"indices": [{
"names": ["am*"],
"privileges": ["read", "view_index_metadata"],
"query": "{\"match\": {\"ACL\": \"acl_luik\"}}"
}],
"run_as": []
}
}
and I would like to split it up in to 2 strings, 1 containing the acl_gent and one conaining acl_luik
the string above can contain more then 2 acl's (and I DON'T know what the name will be)
so I started removing the first and last bracketes :
input = input.Substring(1, input.Length - 2);
but then I can't figure out on how to find the right closing bracket to extract the data.
this was the closest I got
private int closer(string input) {
var i = input.IndexOf('}');
Console.WriteLine(string.Format("[DEBUG] Checking: {0}", input.Substring(0, i).Contains('{')));
if (input.Substring(0, i).Contains('{')) {
return i + closer(input.Substring(i)) + 2;
}
return i;
}
What you have there is a JSON string, a common response from a web service, and there are plenty of libraries to parse JSON, the most common one being JSON.NET. With this you could do something like
JObject myJsonObject = JObject.Parse(myResponse)
and retrieve your strings by their key names, such as
JObject aclString = myJsonObject["acl_luik"];
There are plenty of resources online for parsing JSON strings if you wish to go into more detail.
You have 2 options here:
1) Parse as JSON and get the first 2 objects, this is the better one.
2) Parse using Stack as string of tokens to get what you want, like this:
- Remove the first and last { }
- Using stack, add all { you find, and once you find } remove the first { in the stack.
- Once the stack is empty then you get 1 complete object there, save the indeces while you work and it should be easy to substring with start and end.
I ran into the same problem recently. My solution was to deserialize the string to a json object (in my case a JObject using Json.net) and then accessing the individual members and serializing them to separate strings.
using Newtonsoft.Json.Linq;
public void MakeStrings(string json)
{
var jobject = JsonConvert.DeserializeObject<JObject>(json);
string acl_gent = JsonConvert.SerializeObject(jobject["acl_gent"]);
string acl_luik = JsonConvert.SerializeObject(jobject["acl_luik"]);
}
Can anyone provide some advice, maybe with a code snippet, using C# and json.net to read some nested json?
My json below validates to good json using JSONLint.
I've hit a hurdle that when parsing the json, I am unable to get into the 3rd, 4th, 6th and 8th values nested in the root.
[{
"interactionType": "MathEditorInteraction",
"interactionId": "08506178-22ba-4fa7-a490-c785716f10dc",
"value": "blah blah blah"
},
{
"interactionType": "MathEditorInteraction",
"interactionId": "1134871f-980e-4138-9598-0d4bf480aa97",
"value": "my first value"
},
{
"interactionType": "CanvasInteraction",
"interactionId": "89cd7bec-d0e8-4111-8442-f2ab95a1410b",
"value": "my second value"
},
{
"interactionType": "FillInBlankInteraction",
"interactionId": "7e9350b4-fb85-4f12-869e-227f99f77a73",
"value": "{\"results\":[{\"id\":\"1ac6770e-2093-4b7c-b595-789be8ee6efb\",\"value\":\"my third value\"}]}"
},
{
"interactionType": "FillInBlankInteraction",
"interactionId": "6f1ca6b7-3178-44a7-b8e9-e82d8c51d1fd",
"value": "{\"results\":[{\"id\":\"b7e92fd2-9c7a-4f71-88f9-e7d43e3179b7\",\"value\":\"my fourth value\"}]}"
},
{
"interactionType": "TextBoxInteraction",
"interactionId": "284c43f9-a268-4295-b96d-bc2f6dc30f0e",
"value": "my fifth value"
},
{
"interactionType": "FillInBlankInteraction",
"interactionId": "544b9907-139a-4c78-9671-502153be2697",
"value": "{\"results\":[{\"id\":\"f4e1ba6d-61dd-4eed-9c6f-dafc2701c161\",\"value\":\"my sixth value\"}]}"
},
{
"interactionType": "TextBoxInteraction",
"interactionId": "c0a5a1f0-2cae-42fd-8726-0ad36c11f413",
"value": "my seventh value"
},
{
"interactionType": "FillInBlankInteraction",
"interactionId": "ef6a7b62-8a7b-4b7f-b876-0d78ee6c4c87",
"value": "{\"results\":[{\"id\":\"af39469e-c041-4889-9e28-61a438cf56a3\",\"value\":\"my eight value\"}]}"
},
{
"interactionType": "TextBoxInteraction",
"interactionId": "f04de5b5-8a29-4200-a886-15f7dbd575b6",
"value": "my nineth value"
}]
then some c# that I've been using:
JArray token = JArray.Parse(response); // response = json string above
for (int i = 0; i < token.Count; i++)
{
String value = token[i]["value"].ToString();
}
I could be surprised with the JSON i consume...it could have n-count nested values...the purpose of my code is to get to the bottom-most child with the "value" string.
Is there a way to look at a token[i]["some string"] and see if it contains a JArray or JObject to continue parsing?
EDIT from Timothy's suggestion, I was able to output the values. Almost there.
static string json2 = #"[{""interactionType"": ""MathEditorInteraction"",""interactionId"": ""08506178-22ba-4fa7-a490-c785716f10dc"",""value"": ""blah blah blah""},{""interactionType"": ""MathEditorInteraction"",""interactionId"": ""1134871f-980e-4138-9598-0d4bf480aa97"",""value"": ""my first value""},{""interactionType"": ""CanvasInteraction"",""interactionId"": ""89cd7bec-d0e8-4111-8442-f2ab95a1410b"",""value"": ""my second value""},{""interactionType"": ""FillInBlankInteraction"",""interactionId"": ""7e9350b4-fb85-4f12-869e-227f99f77a73"",""value"": ""{\""results\"":[{\""id\"":\""1ac6770e-2093-4b7c-b595-789be8ee6efb\"",\""value\"":\""my third value\""}]}""},{""interactionType"": ""FillInBlankInteraction"",""interactionId"": ""6f1ca6b7-3178-44a7-b8e9-e82d8c51d1fd"",""value"": ""{\""results\"":[{\""id\"":\""b7e92fd2-9c7a-4f71-88f9-e7d43e3179b7\"",\""value\"":\""my fourth value\""}]}""},{""interactionType"": ""TextBoxInteraction"",""interactionId"": ""284c43f9-a268-4295-b96d-bc2f6dc30f0e"",""value"": ""my fifth value""},{""interactionType"": ""FillInBlankInteraction"",""interactionId"": ""544b9907-139a-4c78-9671-502153be2697"",""value"": ""{\""results\"":[{\""id\"":\""f4e1ba6d-61dd-4eed-9c6f-dafc2701c161\"",\""value\"":\""my sixth value\""}]}""},{""interactionType"": ""TextBoxInteraction"",""interactionId"": ""c0a5a1f0-2cae-42fd-8726-0ad36c11f413"",""value"": ""my seventh value""},{""interactionType"": ""FillInBlankInteraction"",""interactionId"": ""ef6a7b62-8a7b-4b7f-b876-0d78ee6c4c87"",""value"": ""{\""results\"":[{\""id\"":\""af39469e-c041-4889-9e28-61a438cf56a3\"",\""value\"":\""my eight value\""}]}""},{""interactionType"": ""TextBoxInteraction"",""interactionId"": ""f04de5b5-8a29-4200-a886-15f7dbd575b6"",""value"": ""my ninth value""}]";
var x = JsonConvert.DeserializeObject<Interaction[]>(json2);
for (int i = 0; i < x.Length; i++)
{
if (x[i].value.Contains("[{"))
{
var v = JsonConvert.DeserializeObject<Nested>(x[i].value);
Console.WriteLine(v.results[0].value);
}
else
{
Console.WriteLine(x[i].value);
}
}
Console Output:
blah blah blah
my first value
my second value
my third value
my fourth value
my fifth value
my sixth value
my seventh value
my eight value
my ninth value
Still stuck on actually detecting an array deeper than the first level.
You can see my hack to look for "[{" which is not preferred.
EDIT: KUDOS to Jens for helping me arrive at the solution I needed today. See comments below for full explanations.
You can react to JToken.Type if you don't wish to go into deserializing objects.
I actually mostly work with the JSON in a dynamic fasion in C# my self, never deserializing it into strong types, this is mostly because we work with backends where the data structures are defined by the clients and we need to be able to handle much more dynamic data.
https://dotnetfiddle.net/awUSGT
dynamic arr = JArray.Parse(JSON); // response = json string above
foreach (dynamic token in arr)
{
JTokenType type = ((JToken)token.value).Type;
switch (type)
{
case JTokenType.String:
Console.WriteLine(token.value);
break;
case JTokenType.Object:
Console.WriteLine(token.value.results.Last.value);
break;
}
}
Note that for before 8.x or 9.x (can't remember when I posted that fix) something the above will thrown an exception when casting to JToken.
So can instead do:
dynamic arr = JArray.Parse(JSON); // response = json string above
foreach (JObject token in arr)
{
dynamic value = token["value"];
switch (token["value"].Type)
{
case JTokenType.String:
Console.WriteLine(value);
break;
case JTokenType.Object:
Console.WriteLine(value.results.Last.value);
break;
}
}
Now as for one final note, the tool i used to prettify your JSON seemed to strip away some escaping for your values.
I don't know if it was intentional that you have your embeded JSON as strings (Serialized JSON), if so you need to find a way to discover that and then parse that as well.
A loose/relaxed approach could be:
dynamic arr = JArray.Parse(JSON); // response = json string above
foreach (dynamic token in arr)
{
string tokenvalue = (string) token.value;
JToken value = Regex.IsMatch(tokenvalue, "^\\{.*\\}$")
? JToken.Parse(tokenvalue)
: token.value;
switch (value.Type)
{
case JTokenType.String:
Console.WriteLine(value);
break;
case JTokenType.Object:
Console.WriteLine(((dynamic)value).results.Last.value);
break;
}
}
Since I don't know exactly how your "recursive nesting" looks, it is hard to guess, but something along the lines of:
public static void Main()
{
dynamic arr = JArray.Parse(JSON); // response = json string above
foreach (dynamic token in arr)
{
JToken value = ExtractValue(token);
Console.WriteLine(value);
}
}
private static JToken ExtractValue(dynamic token)
{
string tokenvalue = (string) token.value;
JToken value = Regex.IsMatch(tokenvalue, "^\\{.*\\}$")
? JToken.Parse(tokenvalue)
: token.value;
switch (value.Type)
{
case JTokenType.String:
return value;
case JTokenType.Object:
return ExtractValue(((dynamic) value).results.Last);
default:
throw new InvalidOperationException("Could not extract data, unknown json construct.");
}
}
Maybe.
You can easily generate model classes using this service
With this model you can easily Deserialize using Newtonsoft Json
Try using this: JsonConvert.DeserializeObject<Interaction[]>(yourJson);
where Interaction is:
public class Interaction
{
public string interactionType {get;set;}
public string interactionId {get;set;}
public string value {get;set;}
}
Then, for the ones that have a nested JSON, you can then simply parse the value property of them as the following:
public class Nested
{
public Result[] results {get;set;}
}
public class Result
{
public string id {get;set;}
public string value {get;set;}
}
Then parse it like this:
var v = JsonConvert.DeserializeObject<Nested>(x[8].value);
I have been using Json.NET to serialize my objects in memory to json. When I call the following lines of code:
string json = JsonConvert.SerializeObject(template, Formatting.Indented);
System.IO.File.WriteAllText(file, json);
I get the following in a text file:
{
"template": {
"title": "_platform",
"description": "Platform",
"queries": [
{
"query": "// *******************************\n// -- Remove from DurationWindow at the end \n// *******************************\t\n"
}
],
"metadata": ""
}
}
a query is an object I pulled out of the database, that has a string value. When I use xml and write to file (Using XDocument), the new lines in the string (as well as the \t) are properly resolved into tabs and new lines in the file. Is it possible to get the same effect here with json.Net ?
The line-break and tab chars are not valid in JSON values, and JSON.net won't render \t and \n into tab & line break characters actually. To display this nicely, you could do:
var withLineBreaks = json.Replace("\\n", "\n").Replace("\\t", "\t");
However if you do that, the text that you're writing will be invalid JSON, and you'll have to strip out tab and line breaks when you read it back if you want to deserialize it.
I am sterilizing a JSON.Net object, and it contains many arrays. Here is the output I currently get:
"children": [
{
"children": [
{
},
{
}
}
However, just for the ease of reading and comparing, I would like to remove the line breaks between each brace and bracket and between the comma and next brace, so it looks like this:
"children": [ {
"children": [ {
}, {
}
}
I am already sterilizing my JSON with the Formatting.Indented argument, so I would like to know if there is another setting I can change so that JSON.Net sterilizes without the extra line brakes, but retaining the indented formatting.
There is no feature in Json.NET to give you that kind of indentation. You'll either have to do it yourself outside of Json.NET or modify the source code.
Can you split on '{' and then join the array again by spaces?