Метод расширения переименования Newtonsoft для переименования имени свойства в JObject .net

#c# #json #.net #json.net

Вопрос:

Я хочу заменить имя свойства в объекте задания. Я искал несколько решений в Интернете. Узнал, что мы можем расширить функцию переименования от Newtonsoft.
Я также нашел метод расширения.Функция переименования работает для объектов, упомянутых в вопросе, но не для всех.
Мой код выглядит примерно так :

 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);
    }
}
 

Это дает мне ошибку «Не удается переименовать нулевой указатель».
Может ли кто-нибудь сказать мне, что я здесь делаю не так? Заранее большое спасибо.

Ответ №1:

Используйте этот метод для поиска токенов.

 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);
        }
    }
}
 

}

Теперь, чтобы сделать все остальное, используйте этот код :

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

На самом деле в вашем случае Имя находится внутри массива производителей, но o.Property(«Имя») будет искать его только на корневом уровне, что приведет к нулю.

Обновить

Вы сказали, что хотите опустить название продукта, для этого вы можете использовать только небольшое «Если». Измените приведенный выше код с помощью этого.

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

Скрипка для этого кода

Комментарии:

1. Большое спасибо за ваш ответ. Он работает так, как и ожидалось. Но можно ли переименовать только название производителя, а не название продукта ?

2. Я добавил небольшое «если», чтобы выполнить ваш трюк. Это будет работать нормально, но вам нужно правильно проанализировать путь к свойству, если есть еще несколько вложенных свойств с тем же именем. Кстати, я прошу прощения за поздний ответ.