CrazyCoder
CrazyCoder

Reputation: 2388

Newtonsoft Rename extension method to rename a property name in JObject .net

I want to replace a property name in a JObject. I have searched for few solutions online. Found out that we can extend Rename function from Newtonsoft.
I have found the extension method as well.The Rename functionality is working for the JObjects mentioned in the question but not for all.
My code is something like this :

class Program
{
    static void Main(string[] args)
    {
        JObject o = JObject.Parse(@"{
              'Stores': [
                'Lambton Quay',
                'Willis Street'
              ],
              'Manufacturers': [
                {
                  'Name': 'Acme Co',
                  'Products': [
                    {
                      'Name': 'Anvil',
                      'Price': 50
                    }
                  ]
                },
                {
                  'Name': 'Contoso',
                  'Products': [
                    {
                      'Name': 'Elbow Grease',
                      'Price': 99.95
                    },
                    {
                      'Name': 'Headlight Fluid',
                      'Price': 4
                    }
                  ]
                }
              ]
            }");

        o.Property("Name").Rename("LongName");
        Console.WriteLine(o.ToString());
    }
}
public static class NewtonsoftExtensions
{
    public static void Rename(this JToken token, string newName)
    {
        if (token == null)
            throw new ArgumentNullException("token", "Cannot rename a null token");

        JProperty property;

        if (token.Type == JTokenType.Property)
        {
            if (token.Parent == null)
                throw new InvalidOperationException("Cannot rename a property with no parent");

            property = (JProperty)token;
        }
        else
        {
            if (token.Parent == null || token.Parent.Type != JTokenType.Property)
                throw new InvalidOperationException("This token's parent is not a JProperty; cannot rename");

            property = (JProperty)token.Parent;
        }

        // Note: to avoid triggering a clone of the existing property's value,
        // we need to save a reference to it and then null out property.Value
        // before adding the value to the new JProperty.  
        // Thanks to @dbc for the suggestion.

        var existingValue = property.Value;
        property.Value = null;
        var newProperty = new JProperty(newName, existingValue);
        property.Replace(newProperty);
    }
}

This is giving me error "Cannot rename a null pointer".
Can anyone tell me what am I doing wrong here. Many thanks in advance.

Upvotes: 0

Views: 597

Answers (1)

abhishek
abhishek

Reputation: 2992

Use this method to FindTokens.

public static class JsonExtensions
{
public static List<JToken> FindTokens(this JToken containerToken, string name)
{
    List<JToken> matches = new List<JToken>();
    FindTokens(containerToken, name, matches);
    return matches;
}

private static void FindTokens(JToken containerToken, string name, List<JToken> matches)
{
    if (containerToken.Type == JTokenType.Object)
    {
        foreach (JProperty child in containerToken.Children<JProperty>())
        {
            if (child.Name == name)
            {
                matches.Add(child.Value);
            }
            FindTokens(child.Value, name, matches);
        }
    }
    else if (containerToken.Type == JTokenType.Array)
    {
        foreach (JToken child in containerToken.Children())
        {
            FindTokens(child, name, matches);
        }
    }
}

}

Now to do the rest use this code :

foreach (JToken token in o.FindTokens("Name"))
    {
        token.Rename("LongName");
    }

Actually in your case the Name resides inside an array of Manufacturers, but o.Property("Name") will only search it in the root level, that results in null.

Update

You said you want to omit the Product name, you can use just a small If to do it. Change the above code with this one.

foreach (JToken token in o.FindTokens("Name"))
    {
       //Console.WriteLine(token.Path);
       if(!token.Path.Contains("Products"))
       token.Rename("LongName");
    }

Fiddle for this Code

Upvotes: 1

Related Questions