25

I have a json like the following:

{
  "d": {
    "results": [
      {
        "__metadata": {
        },
        "prop1": "value1",
        "prop2": "value2",
        "__some": "value"
      },
      {
        "__metadata": {
        },
        "prop3": "value1",
        "prop4": "value2",
        "__some": "value"
      },
    ]
  }
}

I just want to transform this JSON into a different JSON. I want to strip out the "_metadata" and "_some" nodes from the JSON. I'm using JSON.NET.

live-love
  • 48,840
  • 22
  • 240
  • 204
Mohamed Nuur
  • 5,536
  • 6
  • 39
  • 55

4 Answers4

48

I just ended up deserializing to JObject and recursively looping through that to remove unwanted fields. Here's the function for those interested.

private void removeFields(JToken token, string[] fields)
{
    JContainer container = token as JContainer;
    if (container == null) return;

    List<JToken> removeList = new List<JToken>();
    foreach (JToken el in container.Children())
    {
        JProperty p = el as JProperty;
        if (p != null && fields.Contains(p.Name))
        {
            removeList.Add(el);
        }
        removeFields(el, fields);
    }

    foreach (JToken el in removeList)
    {
        el.Remove();
    }
}
Mohamed Nuur
  • 5,536
  • 6
  • 39
  • 55
  • Thanks! I needed that. Now I can do a Foreach on my JArray's Children collection to remove all my the properties I want. – duyn9uyen Nov 15 '13 at 14:38
  • This really helped me - I wanted to log JSON data with sensitive fields replaced by the length of the data. I was able to get and set p.Value. – 79IT Jul 12 '14 at 10:32
25

Building off of @[Mohamed Nuur]'s answer, I changed it to an extension method which I think works better:

 public static JToken RemoveFields(this JToken token, string[] fields)
    {
        JContainer container = token as JContainer;
        if (container == null) return token;

        List<JToken> removeList = new List<JToken>();
        foreach (JToken el in container.Children())
        {
            JProperty p = el as JProperty;
            if (p != null && fields.Contains(p.Name))
            {
                removeList.Add(el);
            }
            el.RemoveFields(fields);
        }

        foreach (JToken el in removeList)
        {
            el.Remove();
        }

        return token;
    }

Here is unit test:

[TestMethod]
     public void can_remove_json_field_removeFields()
     {
        string original = "{\"d\":{\"results\":[{\"__metadata\":{},\"remove\":\"done\",\"prop1\":\"value1\",\"prop2\":\"value2\",\"__some\":\"value\"},{\"__metadata\":{},\"prop3\":\"value1\",\"prop4\":\"value2\",\"__some\":\"value\"}],\"__metadata\":{\"prop3\":\"value1\",\"prop4\":\"value2\"}}}";
        string expected = "{\"d\":{\"results\":[{\"prop1\":\"value1\",\"prop2\":\"value2\",\"__some\":\"value\"},{\"prop3\":\"value1\",\"prop4\":\"value2\",\"__some\":\"value\"}]}}";
        string actual = JToken.Parse(original).RemoveFields(new string[]{"__metadata", "remove"}).ToString(Newtonsoft.Json.Formatting.None);
        Assert.AreEqual(expected, actual);
     }
Rafi
  • 2,433
  • 1
  • 25
  • 33
2

I would create a new data structure with only the required information and copy the data from the first one. Often that is the simpliest approach. Just an idea.

Anders Lindén
  • 6,839
  • 11
  • 56
  • 109
  • 1
    But I don't know what the data will be. I want to write a generic function that will take a JSON string and a list of properties to exclude (maybe xpath type?) and returns a new JSON string without the properties that are excluded. – Mohamed Nuur Jul 26 '12 at 21:32
-1

This answer applies if you have a JArray with JTokens, not JObjects:

Here is an example:

string json = "[null, null, \"x\", null, null, null, 0,[],[[\"x\"], null,[0],[\"x\"]]]";

    JArray array = JArray.Parse(json);

    // Keep first 3 elements, remove the rest
    int max = array.Count;
    for (int i = 0; i < max - 3; i++)
    {
        JToken elem = array[3];
        array.Remove(elem);
    }

    json = array.ToString(Newtonsoft.Json.Formatting.None);

    Console.WriteLine(json);
live-love
  • 48,840
  • 22
  • 240
  • 204