#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. Я добавил небольшое «если», чтобы выполнить ваш трюк. Это будет работать нормально, но вам нужно правильно проанализировать путь к свойству, если есть еще несколько вложенных свойств с тем же именем. Кстати, я прошу прощения за поздний ответ.