Generic method to determine json is array or object in c# - c#

My project contains too much calls to rest api and sometime i get json array and sometime json object.
Current I have to write same repeated code for each of call to determine the response json is array or object.
So i faced below errors because i dont know the incoming json type.
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'userList' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly. To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array
OR
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[MvcSumit1.Models.User]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly. To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
So to get rid of this problem I want generic method that can handle both of above scenarios.

I want generic method that can handle both of above scenarios.
The below generic method that can parse your incoming json to object or List<object>.
public class Utility
{
public static object JsonParser<T>(string json)
{
try
{
JToken jToken = JToken.Parse(json);
if (jToken is JArray)
return jToken.ToObject<List<T>>();
else if (jToken is JObject)
return jToken.ToObject<T>();
else
return "Unable to cast json to unknown type";
}
catch (JsonReaderException jex)
{
return jex.Message;
}
catch (Exception ex)
{
return ex.Message;
}
}
}
You can use above generic method like below. I created a console app for your demonstration purpose.
class Program
{
static void Main(string[] args)
{
var result = Utility.JsonParser<User>("You json either object or array");
if (result is List<User>)
{
var userList = result as List<User>;
userList.ForEach(user => Console.WriteLine($"Id: {user.Id}, Name: {user.Name}, Age: {user.Age}"));
}
else if (result is User)
{
var user = result as User;
Console.WriteLine($"Id: {user.Id}, Name: {user.Name}, Age: {user.Age}");
}
else if (result is string)
{
Console.WriteLine(result);
}
Console.ReadLine();
}
}
Sample class is used to deserialize your json.
public class User
{
public string Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
Output:
1) By using json with array of objects
string json1 = #"[{'Id':'1','Name':'Mike','Age':43},{'Id':'2','Name':'Anna','Age':56}]";
2) By using json with object only.
string json2 = #"{'Id':'3','Name':'John','Age':24}";
Alternative
The below generic method that can parse your incoming json to object or List<object> and return List<object>.
public class Utility
{
public static List<T> JsonParser<T>(string json)
{
JToken jToken = JToken.Parse(json);
if (jToken is JArray)
{
return jToken.ToObject<List<T>>();
}
else if (jToken is JObject)
{
List<T> lst = new List<T>();
lst.Add(jToken.ToObject<T>());
return lst;
}
else
return new List<T>();
}
}
You can use above generic method like below.
class Program
{
static void Main(string[] args)
{
var userList = Utility.JsonParser<User>("You json either object or array");
if (userList.Count > 0)
{
userList.ForEach(user => Console.WriteLine($"Id: {user.Id}, Name: {user.Name}, Age: {user.Age}"));
}
else
{
//Do code here if your list is empty
}
Console.ReadLine();
}
}

In case we have to deal with different types not just by Array or object, following is my approach:
(note I am using Newtonsoft.Json)
methods1
public bool TryDeserialize(string json, out object target, params Type[] types)
{
foreach (Type type in types)
{
try
{
target = JsonConvert.DeserializeObject(json, type);
return true;
}
catch (Exception)
{
}
}
target = null;
return false;
}
then use it like:
object obj = null;
Type[] types = new Type[] { typeof(TypeA), typeof(List<TypeB>) };
if (TryDeserialize(json, out obj, types))
{
if (obj is TypeA)
{
var r = obj as TypeA;
}
else
{
var r = obj as List<TypeB>;
}
}
or method 2
public bool TryDeserialize<T1, T2>(string json, out object target)
{
try
{
target = JsonConvert.DeserializeObject<T1>(json);
return true;
}
catch (Exception)
{
}
try
{
target = JsonConvert.DeserializeObject<T2>(json);
return true;
}
catch (Exception)
{
target = null;
return false;
}
}
and use it like:
object obj = null;
if (TryDeserialize<TypeA, List<TypeB>>(json, out obj))
{
if (obj is TypeA)
{
var r = obj as TypeA;
}
else
{
var r = obj as List<TypeB>;
}
}

Related

JSON to C#, deserialize property that is either object or array

I have an issue with handling JSON data from an api that I use in my application. The problem is that the JSON contains some properties that are an object when there is an item, and become an array when there are more items. So that's a structure like this:
[
{
"MyObj": {
"Foo": "Bar"
}
},
{
"MyObj": [
{
"Foo": "Bar1"
},
{
"Foo": "Bar2"
}
]
}
]
I've tried several JSON to C# converters, some of them generate a property of type object, the quicktype.io converter generates this:
public class Example
{
[JsonProperty("MyObj")]
public MyObjUnion MyObj { get; set; }
}
public partial class MyObjElement
{
[JsonProperty("Foo")]
public string Foo { get; set; }
}
public struct MyObjUnion
{
public MyObjElement MyObjElement;
public MyObjElement[] MyObjElementArray;
public static implicit operator MyObjUnion(MyObjElement MyObjElement) => new MyObjUnion { MyObjElement = MyObjElement };
public static implicit operator MyObjUnion(MyObjElement[] MyObjElementArray) => new MyObjUnion { MyObjElementArray = MyObjElementArray };
}
internal class MyObjUnionConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(MyObjUnion) || t == typeof(MyObjUnion?);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
{
switch (reader.TokenType)
{
case JsonToken.StartObject:
var objectValue = serializer.Deserialize<MyObjElement>(reader);
return new MyObjUnion { MyObjElement = objectValue };
case JsonToken.StartArray:
var arrayValue = serializer.Deserialize<MyObjElement[]>(reader);
return new MyObjUnion { MyObjElementArray = arrayValue };
}
throw new Exception("Cannot unmarshal type MyObjUnion");
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
var value = (MyObjUnion)untypedValue;
if (value.MyObjElementArray != null)
{
serializer.Serialize(writer, value.MyObjElementArray);
return;
}
if (value.MyObjElement != null)
{
serializer.Serialize(writer, value.MyObjElement);
return;
}
throw new Exception("Cannot marshal type MyObjUnion");
}
public static readonly MyObjUnionConverter Singleton = new MyObjUnionConverter();
}
Although this does work correctly, it's still a bit cumbersome because to get the data you always need to check if it's in the MyObjElement or MyObjElementArray class.
So the question is if there are other, more elegant ways to solve this issue. (Other than changing the API output, which is not mine)
If you know the data structure before hand, I would create a custom data model for the Json file and then deserialise it like so:
CurrencyExchangeRates deserialisedData = JsonConvert.DeserializeObject<CurrencyExchangeRates>(savedData);
foreach (CurrentRate value in deserialisedData.ExchangeRates)
{
rate.ExchangeRates.Add(new CurrentRate { Rate = value.Rate, Timestamp = value.Timestamp });
}
This is how I did that in an application. Hope this helps a little.
You can check and cast each object in your JSON depending the type of object.
For example consider using Newtonsoft.Json library for JSON parsing, you can do the following:
// considering your JSON string
string jsonString = "[{'MyObj':{'Foo':'Bar'}},{'MyObj':[{'Foo':'Bar1'},{'Foo':'Bar2'}]}]";
// parse your JSON into JTokens
var tokens = JToken.Parse(jsonString);
// iterate through all the tokens
foreach (var token in tokens)
{
// your token is a grand child
JToken myObj = token.First.First;
// check if the grand child is array
if (myObj is JArray)
{
// cast the grand child token into MyObj list or array object
IEnumerable<MyObj> objList = myObj.ToObject<List<MyObj>>();
Console.WriteLine("converted to MyObj Array");
}
else if (myObj is JObject) // else if its a non array item
{
// cast the grand child token into MyObj object
MyObj obj = myObj.ToObject<MyObj>();
Console.WriteLine("converted to MyObj");
}
}
// your MyObj Type will look like this:
public class MyObj
{
public string Foo { get; set; }
}

JSON string to C# class object [duplicate]

Is there a way to deserialize JSON content into a C# dynamic type? It would be nice to skip creating a bunch of classes in order to use the DataContractJsonSerializer.
If you are happy to have a dependency upon the System.Web.Helpers assembly, then you can use the Json class:
dynamic data = Json.Decode(json);
It is included with the MVC framework as an additional download to the .NET 4 framework. Be sure to give Vlad an upvote if that's helpful! However if you cannot assume the client environment includes this DLL, then read on.
An alternative deserialisation approach is suggested here. I modified the code slightly to fix a bug and suit my coding style. All you need is this code and a reference to System.Web.Extensions from your project:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Web.Script.Serialization;
public sealed class DynamicJsonConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
return type == typeof(object) ? new DynamicJsonObject(dictionary) : null;
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
public override IEnumerable<Type> SupportedTypes
{
get { return new ReadOnlyCollection<Type>(new List<Type>(new[] { typeof(object) })); }
}
#region Nested type: DynamicJsonObject
private sealed class DynamicJsonObject : DynamicObject
{
private readonly IDictionary<string, object> _dictionary;
public DynamicJsonObject(IDictionary<string, object> dictionary)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
_dictionary = dictionary;
}
public override string ToString()
{
var sb = new StringBuilder("{");
ToString(sb);
return sb.ToString();
}
private void ToString(StringBuilder sb)
{
var firstInDictionary = true;
foreach (var pair in _dictionary)
{
if (!firstInDictionary)
sb.Append(",");
firstInDictionary = false;
var value = pair.Value;
var name = pair.Key;
if (value is string)
{
sb.AppendFormat("{0}:\"{1}\"", name, value);
}
else if (value is IDictionary<string, object>)
{
new DynamicJsonObject((IDictionary<string, object>)value).ToString(sb);
}
else if (value is ArrayList)
{
sb.Append(name + ":[");
var firstInArray = true;
foreach (var arrayValue in (ArrayList)value)
{
if (!firstInArray)
sb.Append(",");
firstInArray = false;
if (arrayValue is IDictionary<string, object>)
new DynamicJsonObject((IDictionary<string, object>)arrayValue).ToString(sb);
else if (arrayValue is string)
sb.AppendFormat("\"{0}\"", arrayValue);
else
sb.AppendFormat("{0}", arrayValue);
}
sb.Append("]");
}
else
{
sb.AppendFormat("{0}:{1}", name, value);
}
}
sb.Append("}");
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (!_dictionary.TryGetValue(binder.Name, out result))
{
// return null to avoid exception. caller can check for null this way...
result = null;
return true;
}
result = WrapResultObject(result);
return true;
}
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
{
if (indexes.Length == 1 && indexes[0] != null)
{
if (!_dictionary.TryGetValue(indexes[0].ToString(), out result))
{
// return null to avoid exception. caller can check for null this way...
result = null;
return true;
}
result = WrapResultObject(result);
return true;
}
return base.TryGetIndex(binder, indexes, out result);
}
private static object WrapResultObject(object result)
{
var dictionary = result as IDictionary<string, object>;
if (dictionary != null)
return new DynamicJsonObject(dictionary);
var arrayList = result as ArrayList;
if (arrayList != null && arrayList.Count > 0)
{
return arrayList[0] is IDictionary<string, object>
? new List<object>(arrayList.Cast<IDictionary<string, object>>().Select(x => new DynamicJsonObject(x)))
: new List<object>(arrayList.Cast<object>());
}
return result;
}
}
#endregion
}
You can use it like this:
string json = ...;
var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new[] { new DynamicJsonConverter() });
dynamic obj = serializer.Deserialize(json, typeof(object));
So, given a JSON string:
{
"Items":[
{ "Name":"Apple", "Price":12.3 },
{ "Name":"Grape", "Price":3.21 }
],
"Date":"21/11/2010"
}
The following code will work at runtime:
dynamic data = serializer.Deserialize(json, typeof(object));
data.Date; // "21/11/2010"
data.Items.Count; // 2
data.Items[0].Name; // "Apple"
data.Items[0].Price; // 12.3 (as a decimal)
data.Items[1].Name; // "Grape"
data.Items[1].Price; // 3.21 (as a decimal)
It's pretty simple using Json.NET:
dynamic stuff = JsonConvert.DeserializeObject("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");
string name = stuff.Name;
string address = stuff.Address.City;
Also using Newtonsoft.Json.Linq:
dynamic stuff = JObject.Parse("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");
string name = stuff.Name;
string address = stuff.Address.City;
Documentation: Querying JSON with dynamic
You can do this using System.Web.Helpers.Json - its Decode method returns a dynamic object which you can traverse as you like.
It's included in the System.Web.Helpers assembly (.NET 4.0).
var dynamicObject = Json.Decode(jsonString);
.NET 4.0 has a built-in library to do this:
using System.Web.Script.Serialization;
JavaScriptSerializer jss = new JavaScriptSerializer();
var d = jss.Deserialize<dynamic>(str);
This is the simplest way.
Simple "string JSON data" to object without any third-party DLL file:
WebClient client = new WebClient();
string getString = client.DownloadString("https://graph.facebook.com/zuck");
JavaScriptSerializer serializer = new JavaScriptSerializer();
dynamic item = serializer.Deserialize<object>(getString);
string name = item["name"];
//note: JavaScriptSerializer in this namespaces
//System.Web.Script.Serialization.JavaScriptSerializer
Note: You can also using your custom object.
Personel item = serializer.Deserialize<Personel>(getString);
You can achieve that with the help of Newtonsoft.Json. Install it from NuGet and then:
using Newtonsoft.Json;
dynamic results = JsonConvert.DeserializeObject<dynamic>(YOUR_JSON);
JsonFx can deserialize JSON content into dynamic objects.
Serialize to/from dynamic types (default for .NET 4.0):
var reader = new JsonReader(); var writer = new JsonWriter();
string input = #"{ ""foo"": true, ""array"": [ 42, false, ""Hello!"", null ] }";
dynamic output = reader.Read(input);
Console.WriteLine(output.array[0]); // 42
string json = writer.Write(output);
Console.WriteLine(json); // {"foo":true,"array":[42,false,"Hello!",null]}
Another way using Newtonsoft.Json:
dynamic stuff = Newtonsoft.Json.JsonConvert.DeserializeObject("{ color: 'red', value: 5 }");
string color = stuff.color;
int value = stuff.value;
I came here to find an answer for .NET Core, without any third-party or additional references. It works fine if you use ExpandoObject with the standard JsonSerializer class. Here is the example that worked for me:
using System.Text.Json;
using System.Dynamic;
dynamic json = JsonSerializer.Deserialize<ExpandoObject>(jsonText);
Console.WriteLine(json.name);
This code prints out the string value of a name property that exists within the JSON text passed into the Deserialize method. Voila - no additional libraries, no nothing. Just .NET core.
Edit: May have a problem for several levels of json with nested elements. Worked for a single-level flat object.
I made a new version of the DynamicJsonConverter that uses Expando Objects. I used expando objects, because I wanted to Serialize the dynamic back into JSON using Json.NET.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Dynamic;
using System.Web.Script.Serialization;
public static class DynamicJson
{
public static dynamic Parse(string json)
{
JavaScriptSerializer jss = new JavaScriptSerializer();
jss.RegisterConverters(new JavaScriptConverter[] { new DynamicJsonConverter() });
dynamic glossaryEntry = jss.Deserialize(json, typeof(object)) as dynamic;
return glossaryEntry;
}
class DynamicJsonConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
var result = ToExpando(dictionary);
return type == typeof(object) ? result : null;
}
private static ExpandoObject ToExpando(IDictionary<string, object> dictionary)
{
var result = new ExpandoObject();
var dic = result as IDictionary<String, object>;
foreach (var item in dictionary)
{
var valueAsDic = item.Value as IDictionary<string, object>;
if (valueAsDic != null)
{
dic.Add(item.Key, ToExpando(valueAsDic));
continue;
}
var arrayList = item.Value as ArrayList;
if (arrayList != null && arrayList.Count > 0)
{
dic.Add(item.Key, ToExpando(arrayList));
continue;
}
dic.Add(item.Key, item.Value);
}
return result;
}
private static ArrayList ToExpando(ArrayList obj)
{
ArrayList result = new ArrayList();
foreach (var item in obj)
{
var valueAsDic = item as IDictionary<string, object>;
if (valueAsDic != null)
{
result.Add(ToExpando(valueAsDic));
continue;
}
var arrayList = item as ArrayList;
if (arrayList != null && arrayList.Count > 0)
{
result.Add(ToExpando(arrayList));
continue;
}
result.Add(item);
}
return result;
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
public override IEnumerable<Type> SupportedTypes
{
get { return new ReadOnlyCollection<Type>(new List<Type>(new[] { typeof(object) })); }
}
}
}
Creating dynamic objects with Newtonsoft.Json works really great.
//json is your string containing the JSON value
dynamic data = JsonConvert.DeserializeObject<dynamic>(json);
Now you can access the data object just like if it was a regular object. This is the JSON object we currently have as an example:
{ "ID":123,"Name":"Jack","Numbers":[1, 2, 3] }
This is how you access it after deserialization:
data.ID //Retrieve the int
data.Name //Retrieve the string
data.Numbers[0] //Retrieve the first element in the array
I use http://json2csharp.com/ to get a class representing the JSON object.
Input:
{
"name":"John",
"age":31,
"city":"New York",
"Childs":[
{
"name":"Jim",
"age":11
},
{
"name":"Tim",
"age":9
}
]
}
Output:
public class Child
{
public string name { get; set; }
public int age { get; set; }
}
public class Person
{
public string name { get; set; }
public int age { get; set; }
public string city { get; set; }
public List<Child> Childs { get; set; }
}
After that I use Newtonsoft.Json to fill the class:
using Newtonsoft.Json;
namespace GitRepositoryCreator.Common
{
class JObjects
{
public static string Get(object p_object)
{
return JsonConvert.SerializeObject(p_object);
}
internal static T Get<T>(string p_object)
{
return JsonConvert.DeserializeObject<T>(p_object);
}
}
}
You can call it like this:
Person jsonClass = JObjects.Get<Person>(stringJson);
string stringJson = JObjects.Get(jsonClass);
PS:
If your JSON variable name is not a valid C# name (name starts with $) you can fix that like this:
public class Exception
{
[JsonProperty(PropertyName = "$id")]
public string id { get; set; }
public object innerException { get; set; }
public string message { get; set; }
public string typeName { get; set; }
public string typeKey { get; set; }
public int errorCode { get; set; }
public int eventId { get; set; }
}
The simplest way is:
Just include this DLL file.
Use the code like this:
dynamic json = new JDynamic("{a:'abc'}");
// json.a is a string "abc"
dynamic json = new JDynamic("{a:3.1416}");
// json.a is 3.1416m
dynamic json = new JDynamic("{a:1}");
// json.a is
dynamic json = new JDynamic("[1,2,3]");
/json.Length/json.Count is 3
// And you can use json[0]/ json[2] to get the elements
dynamic json = new JDynamic("{a:[1,2,3]}");
//json.a.Length /json.a.Count is 3.
// And you can use json.a[0]/ json.a[2] to get the elements
dynamic json = new JDynamic("[{b:1},{c:1}]");
// json.Length/json.Count is 2.
// And you can use the json[0].b/json[1].c to get the num.
Another option is to "Paste JSON as classes" so it can be deserialised quick and easy.
Simply copy your entire JSON
In Visual Studio: Click Edit → Paste Special → Paste JSON as classes
Here is a better explanation n piccas... ‘Paste JSON As Classes’ in ASP.NET and Web Tools 2012.2 RC
You can extend the JavaScriptSerializer to recursively copy the dictionary it created to expando object(s) and then use them dynamically:
static class JavaScriptSerializerExtensions
{
public static dynamic DeserializeDynamic(this JavaScriptSerializer serializer, string value)
{
var dictionary = serializer.Deserialize<IDictionary<string, object>>(value);
return GetExpando(dictionary);
}
private static ExpandoObject GetExpando(IDictionary<string, object> dictionary)
{
var expando = (IDictionary<string, object>)new ExpandoObject();
foreach (var item in dictionary)
{
var innerDictionary = item.Value as IDictionary<string, object>;
if (innerDictionary != null)
{
expando.Add(item.Key, GetExpando(innerDictionary));
}
else
{
expando.Add(item.Key, item.Value);
}
}
return (ExpandoObject)expando;
}
}
Then you just need to having a using statement for the namespace you defined the extension in (consider just defining them in System.Web.Script.Serialization... another trick is to not use a namespace, then you don't need the using statement at all) and you can consume them like so:
var serializer = new JavaScriptSerializer();
var value = serializer.DeserializeDynamic("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");
var name = (string)value.Name; // Jon Smith
var age = (int)value.Age; // 42
var address = value.Address;
var city = (string)address.City; // New York
var state = (string)address.State; // NY
You can use using Newtonsoft.Json
var jRoot =
JsonConvert.DeserializeObject<dynamic>(Encoding.UTF8.GetString(resolvedEvent.Event.Data));
resolvedEvent.Event.Data is my response getting from calling core Event .
Try this:
var units = new { Name = "Phone", Color= "White" };
var jsonResponse = JsonConvert.DeserializeAnonymousType(json, units);
I am using like this in my code and it's working fine
using System.Web.Script.Serialization;
JavaScriptSerializer oJS = new JavaScriptSerializer();
RootObject oRootObject = new RootObject();
oRootObject = oJS.Deserialize<RootObject>(Your JSon String);
Look at the article I wrote on CodeProject, one that answers the question precisely:
Dynamic types with JSON.NET
There is way too much for re-posting it all here, and even less point since that article has an attachment with the key/required source file.
For that I would use JSON.NET to do the low-level parsing of the JSON stream and then build up the object hierarchy out of instances of the ExpandoObject class.
To get an ExpandoObject:
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
Container container = JsonConvert.Deserialize<Container>(jsonAsString, new ExpandoObjectConverter());
Deserializing in JSON.NET can be dynamic using the JObject class, which is included in that library. My JSON string represents these classes:
public class Foo {
public int Age {get;set;}
public Bar Bar {get;set;}
}
public class Bar {
public DateTime BDay {get;set;}
}
Now we deserialize the string WITHOUT referencing the above classes:
var dyn = JsonConvert.DeserializeObject<JObject>(jsonAsFooString);
JProperty propAge = dyn.Properties().FirstOrDefault(i=>i.Name == "Age");
if(propAge != null) {
int age = int.Parse(propAge.Value.ToString());
Console.WriteLine("age=" + age);
}
//or as a one-liner:
int myage = int.Parse(dyn.Properties().First(i=>i.Name == "Age").Value.ToString());
Or if you want to go deeper:
var propBar = dyn.Properties().FirstOrDefault(i=>i.Name == "Bar");
if(propBar != null) {
JObject o = (JObject)propBar.First();
var propBDay = o.Properties().FirstOrDefault (i => i.Name=="BDay");
if(propBDay != null) {
DateTime bday = DateTime.Parse(propBDay.Value.ToString());
Console.WriteLine("birthday=" + bday.ToString("MM/dd/yyyy"));
}
}
//or as a one-liner:
DateTime mybday = DateTime.Parse(((JObject)dyn.Properties().First(i=>i.Name == "Bar").First()).Properties().First(i=>i.Name == "BDay").Value.ToString());
See post for a complete example.
The object you want DynamicJSONObject is included in the System.Web.Helpers.dll from the ASP.NET Web Pages package, which is part of WebMatrix.
There is a lightweight JSON library for C# called SimpleJson.
It supports .NET 3.5+, Silverlight and Windows Phone 7.
It supports dynamic for .NET 4.0
It can also be installed as a NuGet package
Install-Package SimpleJson
Use DataSet(C#) with JavaScript. A simple function for creating a JSON stream with DataSet input. Create JSON content like (multi table dataset):
[[{a:1,b:2,c:3},{a:3,b:5,c:6}],[{a:23,b:45,c:35},{a:58,b:59,c:45}]]
Just client side, use eval. For example,
var d = eval('[[{a:1,b:2,c:3},{a:3,b:5,c:6}],[{a:23,b:45,c:35},{a:58,b:59,c:45}]]')
Then use:
d[0][0].a // out 1 from table 0 row 0
d[1][1].b // out 59 from table 1 row 1
// Created by Behnam Mohammadi And Saeed Ahmadian
public string jsonMini(DataSet ds)
{
int t = 0, r = 0, c = 0;
string stream = "[";
for (t = 0; t < ds.Tables.Count; t++)
{
stream += "[";
for (r = 0; r < ds.Tables[t].Rows.Count; r++)
{
stream += "{";
for (c = 0; c < ds.Tables[t].Columns.Count; c++)
{
stream += ds.Tables[t].Columns[c].ToString() + ":'" +
ds.Tables[t].Rows[r][c].ToString() + "',";
}
if (c>0)
stream = stream.Substring(0, stream.Length - 1);
stream += "},";
}
if (r>0)
stream = stream.Substring(0, stream.Length - 1);
stream += "],";
}
if (t>0)
stream = stream.Substring(0, stream.Length - 1);
stream += "];";
return stream;
}
How to parse easy JSON content with dynamic & JavaScriptSerializer
Please add reference of System.Web.Extensions and add this namespace using System.Web.Script.Serialization; at top:
public static void EasyJson()
{
var jsonText = #"{
""some_number"": 108.541,
""date_time"": ""2011-04-13T15:34:09Z"",
""serial_number"": ""SN1234""
}";
var jss = new JavaScriptSerializer();
var dict = jss.Deserialize<dynamic>(jsonText);
Console.WriteLine(dict["some_number"]);
Console.ReadLine();
}
How to parse nested & complex json with dynamic & JavaScriptSerializer
Please add reference of System.Web.Extensions and add this namespace using System.Web.Script.Serialization; at top:
public static void ComplexJson()
{
var jsonText = #"{
""some_number"": 108.541,
""date_time"": ""2011-04-13T15:34:09Z"",
""serial_number"": ""SN1234"",
""more_data"": {
""field1"": 1.0,
""field2"": ""hello""
}
}";
var jss = new JavaScriptSerializer();
var dict = jss.Deserialize<dynamic>(jsonText);
Console.WriteLine(dict["some_number"]);
Console.WriteLine(dict["more_data"]["field2"]);
Console.ReadLine();
}
I want to do this programmatically in unit tests, I do have the luxury of typing it out.
My solution is:
var dict = JsonConvert.DeserializeObject<ExpandoObject>(json) as IDictionary<string, object>;
Now I can assert that
dict.ContainsKey("ExpectedProperty");
With Cinchoo ETL - an open source library available to parse JSON into a dynamic object:
string json = #"{
""key1"": [
{
""action"": ""open"",
""timestamp"": ""2018-09-05 20:46:00"",
""url"": null,
""ip"": ""66.102.6.98""
}
]
}";
using (var p = ChoJSONReader.LoadText(json)
.WithJSONPath("$..key1")
)
{
foreach (var rec in p)
{
Console.WriteLine("Action: " + rec.action);
Console.WriteLine("Timestamp: " + rec.timestamp);
Console.WriteLine("URL: " + rec.url);
Console.WriteLine("IP address: " + rec.ip);
}
}
Output:
Action: open
Timestamp: 2018-09-05 20:46:00
URL: http://www.google.com
IP address: 66.102.6.98
Sample fiddle: https://dotnetfiddle.net/S0ehSV
For more information, please visit codeproject articles
Disclaimer: I'm the author of this library.
try this way!
JSON example:
[{
"id": 140,
"group": 1,
"text": "xxx",
"creation_date": 123456,
"created_by": "xxx#gmail.co",
"tags": ["xxxxx"]
}, {
"id": 141,
"group": 1,
"text": "xxxx",
"creation_date": 123456,
"created_by": "xxx#gmail.com",
"tags": ["xxxxx"]
}]
C# code:
var jsonString = (File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(),"delete_result.json")));
var objects = JsonConvert.DeserializeObject<dynamic>(jsonString);
foreach(var o in objects)
{
Console.WriteLine($"{o.id.ToString()}");
}
I really like System.Web.Helpers,
dynamic data = Json.Decode(json);
as it supports usage like
var val = data.Members.NumberTen;
or
var val data.Members["10"];
The reference to System.Web.Helpers.DLL is really crazy, it is not even console and desktop app friendly. Here is my attempt to extract the same functionalities as a standalone file directly from https://github.com/mono/aspnetwebstack/tree/master/src/System.Web.Helpers
(Share this as for education purpose only)
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Dynamic;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using Microsoft.CSharp.RuntimeBinder;
using System.Web.Script.Serialization;
using System.IO;
using System.Collections;
using System.Linq;
using System.Globalization;
namespace System.Web.Helpers
{
public static class Json
{
private static readonly JavaScriptSerializer _serializer = CreateSerializer();
public static string Encode(object value)
{
// Serialize our dynamic array type as an array
DynamicJsonArray jsonArray = value as DynamicJsonArray;
if (jsonArray != null)
{
return _serializer.Serialize((object[])jsonArray);
}
return _serializer.Serialize(value);
}
public static void Write(object value, TextWriter writer)
{
writer.Write(_serializer.Serialize(value));
}
public static dynamic Decode(string value)
{
return WrapObject(_serializer.DeserializeObject(value));
}
public static dynamic Decode(string value, Type targetType)
{
return WrapObject(_serializer.Deserialize(value, targetType));
}
public static T Decode<T>(string value)
{
return _serializer.Deserialize<T>(value);
}
private static JavaScriptSerializer CreateSerializer()
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new[] { new DynamicJavaScriptConverter() });
return serializer;
}
internal class DynamicJavaScriptConverter : JavaScriptConverter
{
public override IEnumerable<Type> SupportedTypes
{
get
{
yield return typeof(IDynamicMetaObjectProvider);
yield return typeof(DynamicObject);
}
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
throw new NotSupportedException();
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
IEnumerable<string> memberNames = DynamicHelper.GetMemberNames(obj);
foreach (string item in memberNames)
{
dictionary[item] = DynamicHelper.GetMemberValue(obj, item);
}
return dictionary;
}
}
internal static dynamic WrapObject(object value)
{
// The JavaScriptSerializer returns IDictionary<string, object> for objects
// and object[] for arrays, so we wrap those in different dynamic objects
// so we can access the object graph using dynamic
var dictionaryValues = value as IDictionary<string, object>;
if (dictionaryValues != null)
{
return new DynamicJsonObject(dictionaryValues);
}
var arrayValues = value as object[];
if (arrayValues != null)
{
return new DynamicJsonArray(arrayValues);
}
return value;
}
}
// REVIEW: Consider implementing ICustomTypeDescriptor and IDictionary<string, object>
public class DynamicJsonObject : DynamicObject
{
private readonly IDictionary<string, object> _values;
public DynamicJsonObject(IDictionary<string, object> values)
{
Debug.Assert(values != null);
_values = values.ToDictionary(p => p.Key, p => Json.WrapObject(p.Value),
StringComparer.OrdinalIgnoreCase);
}
public override bool TryConvert(ConvertBinder binder, out object result)
{
result = null;
if (binder.Type.IsAssignableFrom(_values.GetType()))
{
result = _values;
}
else
{
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, "HelpersResources.Json_UnableToConvertType", binder.Type));
}
return true;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = GetValue(binder.Name);
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
_values[binder.Name] = Json.WrapObject(value);
return true;
}
public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
{
string key = GetKey(indexes);
if (!String.IsNullOrEmpty(key))
{
_values[key] = Json.WrapObject(value);
}
return true;
}
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
{
string key = GetKey(indexes);
result = null;
if (!String.IsNullOrEmpty(key))
{
result = GetValue(key);
}
return true;
}
private static string GetKey(object[] indexes)
{
if (indexes.Length == 1)
{
return (string)indexes[0];
}
// REVIEW: Should this throw?
return null;
}
public override IEnumerable<string> GetDynamicMemberNames()
{
return _values.Keys;
}
private object GetValue(string name)
{
object result;
if (_values.TryGetValue(name, out result))
{
return result;
}
return null;
}
}
[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Justification = "This class isn't meant to be used directly")]
public class DynamicJsonArray : DynamicObject, IEnumerable<object>
{
private readonly object[] _arrayValues;
public DynamicJsonArray(object[] arrayValues)
{
Debug.Assert(arrayValues != null);
_arrayValues = arrayValues.Select(Json.WrapObject).ToArray();
}
public int Length
{
get { return _arrayValues.Length; }
}
public dynamic this[int index]
{
get { return _arrayValues[index]; }
set { _arrayValues[index] = Json.WrapObject(value); }
}
public override bool TryConvert(ConvertBinder binder, out object result)
{
if (_arrayValues.GetType().IsAssignableFrom(binder.Type))
{
result = _arrayValues;
return true;
}
return base.TryConvert(binder, out result);
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
// Testing for members should never throw. This is important when dealing with
// services that return different json results. Testing for a member shouldn't throw,
// it should just return null (or undefined)
result = null;
return true;
}
public IEnumerator GetEnumerator()
{
return _arrayValues.GetEnumerator();
}
private IEnumerable<object> GetEnumerable()
{
return _arrayValues.AsEnumerable();
}
IEnumerator<object> IEnumerable<object>.GetEnumerator()
{
return GetEnumerable().GetEnumerator();
}
[SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates", Justification = "This class isn't meant to be used directly")]
public static implicit operator object[](DynamicJsonArray obj)
{
return obj._arrayValues;
}
[SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates", Justification = "This class isn't meant to be used directly")]
public static implicit operator Array(DynamicJsonArray obj)
{
return obj._arrayValues;
}
}
/// <summary>
/// Helper to evaluate different method on dynamic objects
/// </summary>
public static class DynamicHelper
{
// We must pass in "object" instead of "dynamic" for the target dynamic object because if we use dynamic, the compiler will
// convert the call to this helper into a dynamic expression, even though we don't need it to be. Since this class is internal,
// it cannot be accessed from a dynamic expression and thus we get errors.
// Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for details
public static bool TryGetMemberValue(object obj, string memberName, out object result)
{
try
{
result = GetMemberValue(obj, memberName);
return true;
}
catch (RuntimeBinderException)
{
}
catch (RuntimeBinderInternalCompilerException)
{
}
// We catch the C# specific runtime binder exceptions since we're using the C# binder in this case
result = null;
return false;
}
// Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for details
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We want to swallow exceptions that happen during runtime binding")]
public static bool TryGetMemberValue(object obj, GetMemberBinder binder, out object result)
{
try
{
// VB us an instance of GetBinderAdapter that does not implement FallbackGetMemeber. This causes lookup of property expressions on dynamic objects to fail.
// Since all types are private to the assembly, we assume that as long as they belong to CSharp runtime, it is the right one.
if (typeof(Binder).Assembly.Equals(binder.GetType().Assembly))
{
// Only use the binder if its a C# binder.
result = GetMemberValue(obj, binder);
}
else
{
result = GetMemberValue(obj, binder.Name);
}
return true;
}
catch
{
result = null;
return false;
}
}
// Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for details
public static object GetMemberValue(object obj, string memberName)
{
var callSite = GetMemberAccessCallSite(memberName);
return callSite.Target(callSite, obj);
}
// Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for details
public static object GetMemberValue(object obj, GetMemberBinder binder)
{
var callSite = GetMemberAccessCallSite(binder);
return callSite.Target(callSite, obj);
}
// dynamic d = new object();
// object s = d.Name;
// The following code gets generated for this expression:
// callSite = CallSite<Func<CallSite, object, object>>.Create(Binder.GetMember(CSharpBinderFlags.None, "Name", typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));
// callSite.Target(callSite, d);
// typeof(Program) is the containing type of the dynamic operation.
// Dev10 Bug 914027 - Changed the callsite's target parameter from dynamic to object, see comment at top for details
public static CallSite<Func<CallSite, object, object>> GetMemberAccessCallSite(string memberName)
{
var binder = Binder.GetMember(CSharpBinderFlags.None, memberName, typeof(DynamicHelper), new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });
return GetMemberAccessCallSite(binder);
}
// Dev10 Bug 914027 - Changed the callsite's target parameter from dynamic to object, see comment at top for details
public static CallSite<Func<CallSite, object, object>> GetMemberAccessCallSite(CallSiteBinder binder)
{
return CallSite<Func<CallSite, object, object>>.Create(binder);
}
// Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for details
public static IEnumerable<string> GetMemberNames(object obj)
{
var provider = obj as IDynamicMetaObjectProvider;
Debug.Assert(provider != null, "obj doesn't implement IDynamicMetaObjectProvider");
Expression parameter = Expression.Parameter(typeof(object));
return provider.GetMetaObject(parameter).GetDynamicMemberNames();
}
}
}

JSON.Net cannot deserialize json array in custom JsonConverter

I've run into a confusing problem that i cannot seem to solve.
I'm using Json.Net and i've written a custom Json converter to handle a special case in my application.
The issue i've run into is in the deserialize or ReadJson method which is throwing an error when it tires to convert a JSON array into an array of strings:
The exact text of the error is: Unexpected token while deserializing object: PropertyName. Path 'RootPages', line 1, position 13.
As you can see from the inspector, the JProperty it is trying to deserialize (RootPages) has been parsed correctly and is valid JSON.
So i'm not entirely sure what is going on here, any enlightenment would be greatly appreciated..
If relevant, the original JSON string is as follows:
{
"RootPages": [
"TestItem1",
"TestItem2"
],
"Name": "root"
}
EDIT-CODE:
ReadJson Method:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
if (PartialChildPageSerialization) {
var jsonObject = JObject.Load(reader);
var properties = jsonObject.Properties().ToList();
foreach (var property in objectType.GetProperties()) {
var type = property.PropertyType;
object value = null;
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ChildPageCollection<>)) {
var collection = Activator.CreateInstance(type);
var deserializedValue = properties.First(p => p.Name == property.Name).ToObject<string[]>();
type.GetMethod("PolulateFromSerializer").Invoke(collection, new object[] {deserializedValue});
value = collection;
}
else {
value = properties.First(p => p.Name == property.Name).ToObject(type);
}
property.SetValue(existingValue, value);
}
return existingValue;
}
return serializer.Deserialize(reader, objectType);
}
Snippet of the interesting part of ChildPageCollection:
public class ChildPageCollection<T> : IList<T> where T : DataPage
{
public string[] GetNames() => _internalNameList.ToArray();
internal void PolulateFromSerializer(string[] names) {
this.Clear();
_internalNameList.AddRange(names);
_hasFullList = false;
}
private void CheckFullList() {
if(!_hasFullList)
throw new InvalidOperationException("Collection has not been fully loaded, and full list is not avialable.");
}
private readonly List<T> _internalList = new List<T>();
private readonly List<string> _internalNameList = new List<string>();
private bool _hasFullList = true;
...
}
I expect this is because the first property is an object with a property called 'RootPages' which is a string[].
Unfortunately from the looks of your screenshots you are trying to turn an object into a string array.
This should work in the example you've given:
properties.First(p => p.Name == property.Name).Select(o => o.Children().Values<string>()).First().ToArray();
In place of:
properties.First(p => p.Name == property.Name).ToObject<string[]>();

Deserialize an Anonymous Type From a Collection

I have my serialized JSON in this format:
string json = #"[{"Name": "std_id","Value": "111"}, {"Name": "cust_id","Value": "444"}]"
How do I deserialize it to a single anonymous object like this:
var paramObj = new {"std_id" = 111, "cust_id" = 444}
Since you said the values of the Name and Value properties in your JSON objects can vary, you will not be able to deserialize to an anonymous object. Anonymous types are defined at compile-time, which means you need to know the property names ahead of time to be able to define them. The only way to get around that is code generation, which I think is going to be overkill for this situation. Instead, I would suggest you deserialize into a JObject with a dynamic variable. This will get you pretty close to what you want. Here's how:
string json = #"[
{ ""Name"": ""std_id"", ""Value"": ""111"" },
{ ""Name"": ""cust_id"", ""Value"": ""444"" }
]";
dynamic obj = new JObject(JArray.Parse(json)
.Select(t => new JProperty((string)t["Name"], t["Value"])));
From there, you can access the properties like you would for an anonymous type (assuming you know what they are):
Console.WriteLine(obj.std_id);
Console.WriteLine(obj.cust_id);
If you don't know what the properties are, you can enumerate them like a dictionary:
foreach (var prop in obj)
{
Console.WriteLine(prop.Name + ": " + prop.Value);
}
Fiddle: https://dotnetfiddle.net/MRY2ny
Why anonymous object? you should deserialize to a type like below
public class RootObject
{
public string Name { get; set; }
public string Value { get; set; }
}
Then what you actually have is IEnumerable<RootObjct>. You can use use Linq and select First() from it like
RootObject = RootObjects.FirstOrDefault()
You could deserialize it into a dynamic. Like this:
var serializer = new JavaScriptSerializer();
var deserializedResult = serializer.Deserialize<dynamic>(json);
Reference:
JavaScriptSerializer Class
var definition = new { Name = "" };
string json1 = #"{'Name':'James'}";
var customer1 = JsonConvert.DeserializeAnonymousType(json1, definition);
Console.WriteLine(customer1.Name);
string json2 = #"{'Name':'Mike'}";
var customer2 = JsonConvert.DeserializeAnonymousType(json2, definition);
Console.WriteLine(customer2.Name);
source http://www.newtonsoft.com/json/help/html/DeserializeAnonymousType.htm
I know that this solution isn't perfect, but it works for the example provided by you and returns result that looks like paramObj in your example.
The idea is to create a custom Json converter.
First, let's create a DTO class to present a name-value item of incomming JSON.
public class NameValueJsonItem
{
public string Name { get; set; }
public string Value { get; set; }
}
Converter implementation:
public class DynamicJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return true;
}
public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
if (token == null || token.Type != JTokenType.Array)
{
return null;
}
List<NameValueJsonItem> parsedJson = token.ToObject<List<NameValueJsonItem>>();
ExpandoObject result = new ExpandoObject();
foreach (NameValueJsonItem item in parsedJson)
{
if (!String.IsNullOrEmpty(item.Name))
{
(result as IDictionary<string, object>)[item.Name] = item.Value;
}
}
return result;
}
public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Sure, you can make it more safe by adding some exceptions handling etc inside the method if you want.
You can use this converter like that:
dynamic result = JsonConvert.DeserializeObject<dynamic>(json, new DynamicJsonConverter());
Hope it will help.

Newtonsoft JSon Deserialize into Primitive type

In my C# program, I am querying a webservice and getting a reply stream back in JSON that looks something like this:
{"val":12345.12},{"val":23456.23},{"val":34567.01},...
or, with possibly more than 1 value per reply object:
{"val1":12345.12,"val2":1},{"val1":23456.23,"val2":3},....
And I have the following code utilizing the Newtonsoft.Json library that parses the stream and performs some action on each parsed object, one at a time:
public void ParseReply<T>(StreamReader sr, Action<T> action)
{
using (var reader = new JsonTextReader(sr))
{
var ser = new JsonSerializer();
while (reader.Read())
{
if (reader.TokenType == JsonToken.EndArray)
break;
action(ser.Deserialize<T>(reader));
}
}
}
So, in the case of the second result, I have the following code:
public class MyObject
{
public double val1;
public double val2;
}
and then:
myJson.ParseReply<MyObject>(sr, obj => ...);
works perfectly.
But, in the case of the first reply (1 value per object), if I try and use my method in the following way:
myJson.ParseReply<double>(sr, dbl => ...);
I get an error saying:
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Double' because the type requires a JSON primitive value (e.g. string, number, boolean, null) to deserialize correctly.
To fix this error either change the JSON to a JSON primitive value (e.g. string, number, boolean, null) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
I'm really lost / curious how I could update my code to be able to parse both of these correctly and I'm a bit lost on this error message. Any help would REALLY be appreciated!!
If you change your static method to return an IEnumerable<T> rather than taking an Action<T>, you will be able to chain together Enumerable and LINQ to JSON methods in a very concise and natural way. Thus if you have:
public static class JsonExtensions
{
public static IEnumerable<T> ParseArray<T>(this TextReader textReader)
{
using (var reader = new JsonTextReader(textReader))
{
bool inArray = false;
var ser = JsonSerializer.CreateDefault();
while (reader.Read())
{
if (reader.TokenType == JsonToken.Comment)
continue;
if (reader.TokenType == JsonToken.StartArray && !inArray)
{
inArray = true;
continue;
}
if (reader.TokenType == JsonToken.EndArray)
break;
yield return ser.Deserialize<T>(reader);
}
}
}
public static IEnumerable<JToken> DescendantsAndSelf(this JToken node)
{
// This method should be present on JToken but is only present on JContainer.
if (node == null)
return Enumerable.Empty<JToken>();
var container = node as JContainer;
if (container != null)
return container.DescendantsAndSelf();
else
return new[] { node };
}
public static bool IsNumeric(this JTokenType type) { return type == JTokenType.Integer || type == JTokenType.Float; }
public static bool IsNumeric(this JToken token) { return token == null ? false : token.Type.IsNumeric(); }
}
You can do:
var json = #"[{""val"":12345.12},{""val"":23456.23},{""val"":34567.01}]";
// Select all properties named "val" and transform their values to doubles.
foreach (var val in new StringReader(json).ParseArray<JToken>()
.Select(t => (double)t.SelectToken("val")))
{
Debug.WriteLine(val);
}
// Select all primitive numeric values
foreach (var val in new StringReader(json).ParseArray<JToken>()
.SelectMany(t => t.DescendantsAndSelf())
.Where(t => t.IsNumeric())
.Select(t => (double)t))
{
Debug.WriteLine(val);
}

Categories

Resources