Remove fields from JSON dynamically using Json.Net

后端 未结 2 1509
深忆病人
深忆病人 2020-12-07 03:13

I have some JSON input, the shape of which I cannot predict, and I have to make some transformations (to call it something) so that some fields are not logged. For instance,

2条回答
  •  情歌与酒
    2020-12-07 03:17

    You can parse your JSON to a JContainer (which is either an object or array), then search the JSON hierarchy using DescendantsAndSelf() for properties with names that match some Regex, or string values that match a Regex, and remove those items with JToken.Remove().

    For instance, given the following JSON:

    {
      "Items": [
        {
          "id": 5,
          "name": "Peter",
          "password": "some pwd"
        },
        {
          "id": 5,
          "name": "Peter",
          "password": "some pwd"
        }
      ],
      "RootPasswrd2": "some pwd",
      "SecretData": "This data is secret",
      "StringArray": [
        "I am public",
        "This is also secret"
      ]
    }
    

    You can remove all properties whose name includes "pass.*w.*r.*d" as follows:

    var root = (JContainer)JToken.Parse(jsonString);
    
    var nameRegex = new Regex(".*pass.*w.*r.*d.*", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
    var query = root.DescendantsAndSelf()
        .OfType()
        .Where(p => nameRegex.IsMatch(p.Name));
    query.RemoveFromLowestPossibleParents();
    

    Which results in:

    {
      "Items": [
        {
          "id": 5,
          "name": "Peter"
        },
        {
          "id": 5,
          "name": "Peter"
        }
      ],
      "SecretData": "This data is secret",
      "StringArray": [
        "I am public",
        "This is also secret"
      ]
    }
    

    And you can remove all string values that include the substring secret by doing:

    var valueRegex = new Regex(".*secret.*", RegexOptions.IgnoreCase);
    var query2 = root.DescendantsAndSelf()
        .OfType()
        .Where(v => v.Type == JTokenType.String && valueRegex.IsMatch((string)v));
    query2.RemoveFromLowestPossibleParents();
    
    var finalJsonString = root.ToString();
    

    Which when applied after the first transform results in:

    {
      "Items": [
        {
          "id": 5,
          "name": "Peter"
        },
        {
          "id": 5,
          "name": "Peter"
        }
      ],
      "StringArray": [
        "I am public"
      ]
    }
    

    For convenience, I am using the following extension methods:

    public static partial class JsonExtensions
    {
        public static TJToken RemoveFromLowestPossibleParent(this TJToken node) where TJToken : JToken
        {
            if (node == null)
                return null;
            JToken toRemove;
            var property = node.Parent as JProperty;
            if (property != null)
            {
                // Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should
                toRemove = property;
                property.Value = null;
            }
            else
            {
                toRemove = node;
            }
            if (toRemove.Parent != null)
                toRemove.Remove();
            return node;
        }
    
        public static IEnumerable RemoveFromLowestPossibleParents(this IEnumerable nodes) where TJToken : JToken
        {
            var list = nodes.ToList();
            foreach (var node in list)
                node.RemoveFromLowestPossibleParent();
            return list;
        }
    }
    

    Demo fiddle here.

提交回复
热议问题