2012-07-27 6 views
8

Ho una stringa che rappresenta JSON e voglio rinominare alcune proprietà usando JSON.NET. Ho bisogno di una funzione generica da usare per qualsiasi JSON. Qualcosa di simile:Json.net rinomina proprietà

public static void Rename(JContainer container, Dictiontionary<string, string> mapping) 
{ 
    foreach (JToken el in container.Children()) 
    { 
    JProperty p = el as JProperty; 
    if(el != null && mapping.ContainsKey(p.Name)) 
    { 
     // **RENAME THIS NODE!!** 
    } 

    // recursively rename nodes 
    JContainer pcont = el as JContainer; 
    if(pcont != null) 
    { 
     Rename(pcont, mapping); 
    } 
    } 
} 

Come fare ??

risposta

13

Suggerirei di ricostruire il JSON con le proprietà ridenominate. Non penso che dovresti preoccuparti dei rigori per la velocità, perché di solito non è un problema. Ecco come puoi farlo.

public static JToken Rename(JToken json, Dictionary<string, string> map) 
{ 
    return Rename(json, name => map.ContainsKey(name) ? map[name] : name); 
} 

public static JToken Rename(JToken json, Func<string, string> map) 
{ 
    JProperty prop = json as JProperty; 
    if (prop != null) 
    { 
     return new JProperty(map(prop.Name), Rename(prop.Value, map)); 
    } 

    JArray arr = json as JArray; 
    if (arr != null) 
    { 
     var cont = arr.Select(el => Rename(el, map)); 
     return new JArray(cont); 
    } 

    JObject o = json as JObject; 
    if (o != null) 
    { 
     var cont = o.Properties().Select(el => Rename(el, map)); 
     return new JObject(cont); 
    } 

    return json; 
} 

Ed ecco un esempio di utilizzo:

var s = @"{ ""A"": { ""B"": 1, ""Test"": ""123"", ""C"": { ""Test"": [ ""1"", ""2"", ""3"" ] } } }"; 
var json = JObject.Parse(s); 

var renamed = Rename(json, name => name == "Test" ? "TestRenamed" : name); 
renamed.ToString().Dump(); // LINQPad output 

var dict = new Dictionary<string, string> { { "Test", "TestRenamed"} }; 
var renamedDict = Rename(json, dict); 
renamedDict.ToString().Dump(); // LINQPad output 
+0

Grazie Dmitry, questo è perfetto! –

+0

Ci possono essere alcuni bug minori, ma puoi correggerli tu stesso se ne trovi uno :) –

3

Usiamo questo approccio. Puoi trovare la proprietà che desideri utilizzando il SelectToken() di JObject. Sì, supporta JsonPath.

public static class NewtonsoftExtensions 
{ 
    public static void Rename(this JToken token, string newName) 
    { 
     var parent = token.Parent; 
     if (parent == null) 
      throw new InvalidOperationException("The parent is missing."); 
     var newToken = new JProperty(newName, token); 
     parent.Replace(newToken); 
    } 
} 
+0

Un po 'sorpreso che tu non abbia fatto notare che questo è in realtà parte del framework, che è stato fatto da te: https://github.com/abibell /Newtonsoft.Json/commit/12f3f32401074a84b3d186956e59e56c9e8781cb :-) –

+0

Ciao Alastair, volevo la funzione. Ho fatto cambiamenti di caffè per questo e ho inviato una richiesta di pull. Non è stato accettato dal proprietario con un motivo "Non mi piace" .https: //github.com/JamesNK/Newtonsoft.Json/pull/549 –

+1

@AbiBellamkonda, sto provando a utilizzare questo metodo di estensione per rinominare un oggetto JProperty, ma ottengo l'eccezione "Impossibile aggiungere Newtonsoft.Json.Linq.JProperty a Newtonsoft.Json.Linq.JProperty." da questo bit di codice: 'new JProperty (newName, token)'. – Gyromite