2

I have a JSON string as shown below. I want to remove the empty array objects from it programmatically so that I can convert it to a DataTable.

Here is an example of my JSON:

{
   "result":[
     {
       "id":"1",
       "name": "Temp",
       "property":[]
     },
     {
       "id":"2",
       "name": "Temp2",
       "property":[]
     }
  ]
}

You can see that the property member in each result is an empty array. Any suggestion on how I can remove it?

Currently I'm doing the following to convert the JSON to a DataTable:

DataTable dt = JsonConvert.DeserializeObject<DataTable>(data["result"].ToString());

When I manually remove the array property, the conversion works perfectly.

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
Mohammed Zain
  • 21
  • 1
  • 4
  • 2
    Don't go straight to a datatable, deserialize to a custom class then convert that to a datatable (if you need to). – Crowcoder May 23 '16 at 11:42

4 Answers4

1

This is how you can remove 'property' array from JSON and parse the remaining data into DataTable:

foreach (var item in data["result"])
{
      JObject obj = (JObject)item;
      obj.Property("property").Remove();
}

DataTable dt = JsonConvert.DeserializeObject<DataTable>(data["result"].ToString());
Saadi
  • 2,211
  • 4
  • 21
  • 50
  • Is there an option to remove the empty array member without making a class? I'm try to create a dynamic function that can remove any empty array member, the JSON string may be different at times. – Mohammed Zain May 23 '16 at 12:31
  • ok. I'm editing the source code according to your need. You want to remove array 'property' from json. – Saadi May 23 '16 at 12:58
1

You could use a regex to remove the properties with empty arrays from the json string itself. Here is one that uses two regexes, one to kill the properties with empty arrays and the other to kill any erroneous commas that are left over.

var json = "{\"prop\": [], \"prop2\": \"test\", \"propqw\": []}";
var removeEmpty = new Regex("\\s*\"[^\"]+\":\\s*\\[\\]\\,?");
var removeComma = new Regex(",(?=\\s*})");
var result = removeEmpty.Replace(json, "");
result = removeComma.Replace(result, "");

There may be a slightly cleaner way than this but I couldn't quickly find a single regex way to remove properties and clean potential illegal commas.

ndonohoe
  • 9,320
  • 2
  • 18
  • 25
  • 1
    I would not recommend using Regex for parsing/manipulating JSON. It is too error prone. Use JObjects instead. – Brian Rogers May 23 '16 at 16:24
  • Agree with Brian Rogers, Regex is more likely to cause future issues and there are better ways of dealing with this issue. – Noldy Aug 10 '16 at 12:57
1

You can use Json.Net's LINQ-to-JSON API to remove the empty array properties (regardless of their names) and then convert the result to a DataTable:

JObject data = JObject.Parse(json);

var emptyArrayProperties = data["result"]
    .Children<JObject>()
    .SelectMany(jo => jo.Properties())
    .Where(jp => jp.Value.Type == JTokenType.Array && !jp.Value.HasValues)
    .ToList();

foreach (JProperty prop in emptyArrayProperties)
{
    prop.Remove();
}

DataTable table = obj["result"].ToObject<DataTable>();

Fiddle: https://dotnetfiddle.net/rVIijq

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
1

To move straight to the point with reference to the above issue, we could resolve that using IContractResolver which works as follows:

  1. Create a class in your project model folder, for instance MyClass.
  2. add the following code

    public class MyClass : DefaultContractResolver
    {
    
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            JsonProperty property = base.CreateProperty(member, memberSerialization);
            property.ShouldSerialize = obj =>
            {
                if (property.PropertyType.Name.Contains("ICollection"))
                {
                    return (property.ValueProvider.GetValue(obj) as dynamic).Count > 0;
                }
                return true;
            };
            return property;
        }
    }
    
  3. DefaultContractResolver comes from the Newtonsoft.Json.Serialization so you need to install Newtonsoft.Json from nuget package manager and add * using Newtonsoft.Json * and * using Newtonsoft.Json.Serialization; * to MyClass.cs file we created.

    1. CreateProperty and MemberInfo comes from System.Reflection; so add * using System.Reflection; * in order to import them.

    2. We want to make it accessible across the project domain so we will instantiate the class in the Global.asax file, so locate and open the Global.asax and add the following to the protected void Application_Start() method.

    GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
    GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
    GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.DefaultValueHandling = DefaultValueHandling.Ignore;
    GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.Formatting = Formatting.Indented;
    GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new MyClass();
    GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
    

    NB: make sure to add * using Newtonsoft.Json; * and * using YourProjectName.Models; * in your Global.asax file

Voila!!!.... You may run your project to see the outcome.

Zoe
  • 27,060
  • 21
  • 118
  • 148