2017-02-11 5 views
1

J'essaie d'utiliser JsonConvert.DeserializeObject (string) pour désérialiser une chaîne dans un jobject qui peut utiliser avec dynamic pour accéder au document json à la volée. Cependant je veux éviter de savoir le boîtier du document que je peux taperjson.net custom jobject deserialization

dynamic document = JsonConvert.DeserializeObject(someString); 
Console.WriteLine(document.some.path.here.name); 

et le faire fonctionner sur {"Some":{"path":{"HERE":{"Name":"test"}}} Je ne peux pas savoir comment créer une classe personnalisée pour json.net qui le fera pour moi, en supprimant essentiellement la sensibilité à la casse sur le jobject (ou peut-être transformer toutes les propriétés en minuscules)

+1

Vous pouvez essayer quelque chose comme ceci: http://stackoverflow.com/questions/9247478/pascal-case-dynamic-properties-with-json-net –

Répondre

1

Pour convertir récursive toutes les propriétés dans une hiérarchie JToken en minuscules, vous pouvez utiliser la méthode extension suivante:

public static class JsonExtensions 
{ 
    public static TJToken RenamePropertiesToLowerInvariant<TJToken>(this TJToken root) where TJToken : JToken 
    { 
     return root.RenameProperties(s => s.ToLowerInvariant()); 
    } 

    public static TJToken RenameProperties<TJToken>(this TJToken root, Func<string, string> map) where TJToken : JToken 
    { 
     if (map == null) 
      throw new ArgumentNullException(); 
     if (root == null) 
      return null; 
     if (root is JProperty) 
     { 
      return RenameReplaceProperty(root as JProperty, map, -1) as TJToken; 
     } 
     else 
     { 
      foreach (IList<JToken> obj in root.DescendantsAndSelf().OfType<JObject>()) 
       for (int i = obj.Count - 1; i >= 0; i--) 
        RenameReplaceProperty((JProperty)obj[i], map, i); 
      return root; 
     } 
    } 

    public static IEnumerable<JToken> DescendantsAndSelf(this JToken node) 
    { 
     if (node == null) 
      return Enumerable.Empty<JToken>(); 
     var container = node as JContainer; 
     if (container != null) 
      return container.DescendantsAndSelf(); 
     else 
      return new[] { node }; 
    } 

    private static JProperty RenameReplaceProperty(JProperty property, Func<string, string> map, int index) 
    { 
     // JProperty.Name is read only so it will need to be replaced in its parent. 
     if (property == null) 
      return null; 
     var newName = map(property.Name); 
     if (newName == property.Name) 
      return property; 
     var value = property.Value; 
     // Setting property.Value to null on the old property prevents the child JToken hierarchy from getting recursively cloned when added to the new JProperty 
     // See https://github.com/JamesNK/Newtonsoft.Json/issues/633#issuecomment-133358110 
     property.Value = null; 
     var newProperty = new JProperty(newName, value); 
     IList<JToken> container = property.Parent; 
     if (container != null) 
     { 
      if (index < 0) 
       index = container.IndexOf(property); 
      container[index] = newProperty; 
     } 
     return newProperty; 
    } 
} 

Puis faire

dynamic document = JsonConvert.DeserializeObject<JToken>(someString).RenamePropertiesToLowerInvariant(); 

Cependant, JObject est sensible à la casse et ne fournit aucun constructeur d'utiliser un comparateur cas invariant dans sa JPropertyKeyedCollection. Et JObjectDynamicProxy.TryGetMember() semble faire une simple recherche et non une recherche insensible à la casse.

Donc, à moins que vous pouvez obtenir this answer à travailler, si vous avez besoin d'un objet dynamique insensible à la casse, vous pouvez prendre l'un des remplaçants pour ExpandoObject de How to set ExpandoObject's dictionary as case insensitive? puis créez votre propre version de ExpandoObjectConverter désérialiser votre type de expando alternatif.

+0

J'ai peur de la différence de performance entre jobject et mon propre objet expando, mais semble être la route acceptée en fonction de tous les liens fournis dans ce q –

0

Tout d'abord, assurez-vous d'avoir téléchargé la dernière version de Json.NET (http://ud.ht/OrbT). Ensuite, utilisez le code suivant, car la dernière version vous permet de le faire, comme suit:

var str = {"Some":{"path":{"HERE":{"Name":"test"}}}; 
dynamic document = JObject.Parse(str); 
Console.WriteLine(document.Some.path.HERE.Name); 
+0

en quelque sorte il ne fonctionne pas pour moi, il doit correspondre à l'enveloppe json , document.some est une référence nulle –

+0

Etes-vous sûr de ça? Cela ne fonctionne pas dans Json.NET 6.0 - voir https://dotnetfiddle.net/2ooj6b. Et ['JObjectDynamicProxy.TryGetMember()'] (https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Linq/JObject.cs#L807) est inchangé depuis, faisant un correspondance sensible à la casse. Je ne trouve également rien de pertinent dans les [notes de version] (https://github.com/JamesNK/Newtonsoft.Json/releases). – dbc

+0

Mon ami, vous les noms de variables sont sensibles à la casse. Essayez ceci: Utilisez ceci: Console.WriteLine (document.Some.path.HERE.Name); http://ud.ht/Gzwx – AHBagheri