2011-09-24 3 views
15

Sto cercando di utilizzare JsonPath per .NET (http://code.google.com/p/jsonpath/downloads/list) e non riesco a trovare un esempio di come analizzare una stringa Json e una stringa JsonPath e ottenere un risultato.Come utilizzare l'esempio C# usando JsonPath?

Qualcuno ha usato questo?

+4

potrei suggerire Json.NET come JSON alternativa parser (http://james.newtonking.com/pages/json-net.aspx) –

+0

Ha una funzionalità simile a JsonPath? –

+3

Qualcosa di simile a XPath? Lo fa. Controlla la funzionalità SelectToken di JSON.NET. È possibile utilizzare un'espressione stringa per ottenere JSON. Ad esempio: http: // StackOverflow.it/questions/1698175/what-is-the-json-net-equivilant-of-xmls-xpath-selectnodes-selectsinglenode –

risposta

21

Il problema che si verifica è che la versione C# di JsonPath non include un parser Json, quindi è necessario utilizzarlo con un altro framework Json che gestisca la serializzazione e la deserializzazione.

Il modo in cui funziona JsonPath consiste nell'utilizzare un'interfaccia denominata IJsonPathValueSystem per attraversare oggetti JSON analizzati. JsonPath viene fornito con un BasicValueSystem integrato che utilizza l'interfaccia IDictionary per rappresentare gli oggetti Json e l'interfaccia IList per rappresentare gli array JSON.

È possibile creare i propri oggetti JSON compatibili con BasicValueSystem costruendoli utilizzando gli inizializzatori di raccolta C#, ma questo non è di grande utilità quando ad esempio il JSON arriva sotto forma di stringhe da un server remoto.

Quindi, se solo si potesse prendere una stringa Json e analizzarla in una struttura annidata di oggetti IDictionary, IList e valori primitivi, si potrebbe quindi utilizzare JsonPath per filtrarlo! Per fortuna, possiamo usare Json.NET che ha buone capacità di serializzazione e deserializzazione per fare quella parte del lavoro.

Sfortunatamente, Json.NET non deserializza le stringhe di Json in un formato compatibile con lo BasicValueSystem. Quindi il primo compito per l'utilizzo di JsonPath con Json.NET è scrivere un JsonNetValueSystem che implementa IJsonPathValueSystem e che comprenda gli oggetti JObject, gli array JArray e i valori JValue prodotti da JObject.Parse.

Quindi scaricare sia JsonPath che Json.NET e inserirli in un progetto C#. Quindi aggiungere questa classe per quel progetto:

public sealed class JsonNetValueSystem : IJsonPathValueSystem 
{ 
    public bool HasMember(object value, string member) 
    { 
     if (value is JObject) 
       return (value as JObject).Properties().Any(property => property.Name == member); 
     if (value is JArray) 
     { 
      int index = ParseInt(member, -1); 
      return index >= 0 && index < (value as JArray).Count; 
     } 
     return false; 
    } 

    public object GetMemberValue(object value, string member) 
    { 
     if (value is JObject) 
     { 
      var memberValue = (value as JObject)[member]; 
      return memberValue; 
     } 
     if (value is JArray) 
     { 
      int index = ParseInt(member, -1); 
      return (value as JArray)[index]; 
     } 
     return null; 
    } 

    public IEnumerable GetMembers(object value) 
    { 
     var jobject = value as JObject; 
     return jobject.Properties().Select(property => property.Name); 
    } 

    public bool IsObject(object value) 
    { 
     return value is JObject; 
    } 

    public bool IsArray(object value) 
    { 
     return value is JArray; 
    } 

    public bool IsPrimitive(object value) 
    { 
     if (value == null) 
      throw new ArgumentNullException("value"); 

     return value is JObject || value is JArray ? false : true; 
    } 

    private int ParseInt(string s, int defaultValue) 
    { 
     int result; 
     return int.TryParse(s, out result) ? result : defaultValue; 
    } 
} 

Ora con tutte e tre di questi pezzi possiamo scrivere un programma di esempio JsonPath:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var input = @" 
       { ""store"": { 
        ""book"": [ 
         { ""category"": ""reference"", 
          ""author"": ""Nigel Rees"", 
          ""title"": ""Sayings of the Century"", 
          ""price"": 8.95 
         }, 
         { ""category"": ""fiction"", 
          ""author"": ""Evelyn Waugh"", 
          ""title"": ""Sword of Honour"", 
          ""price"": 12.99 
         }, 
         { ""category"": ""fiction"", 
          ""author"": ""Herman Melville"", 
          ""title"": ""Moby Dick"", 
          ""isbn"": ""0-553-21311-3"", 
          ""price"": 8.99 
         }, 
         { ""category"": ""fiction"", 
          ""author"": ""J. R. R. Tolkien"", 
          ""title"": ""The Lord of the Rings"", 
          ""isbn"": ""0-395-19395-8"", 
          ""price"": 22.99 
         } 
        ], 
        ""bicycle"": { 
         ""color"": ""red"", 
         ""price"": 19.95 
        } 
       } 
      } 
     "; 
     var json = JObject.Parse(input); 
     var context = new JsonPathContext { ValueSystem = new JsonNetValueSystem() }; 
     var values = context.SelectNodes(json, "$.store.book[*].author").Select(node => node.Value); 
     Console.WriteLine(JsonConvert.SerializeObject(values)); 
     Console.ReadKey(); 
    } 
} 

che produce questo output:

["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"] 

Questo esempio è basato sull'esempio Javascript nel sito JsonPath:

+2

Invece di scrivere molto codice e usare due librerie, non sarebbe più semplice usare solo Json.Net come questo: JObject json = JObject.Parse (@input); var values ​​= json.SelectToken ("store.book"). Valori ("autore"); –

+0

Questa risposta risponde alla domanda. Ovviamente ci sono molti altri approcci che dipendono dal problema da risolvere. –

+0

Grazie! Esattamente quello di cui avevo bisogno. SelectToken di Json.Net non ha la funzionalità di cui ho bisogno. –

2

Per coloro che non amano LINQ (NET 2.0):

namespace JsonPath 
{ 


    public sealed class JsonNetValueSystem : IJsonPathValueSystem 
    { 


     public bool HasMember(object value, string member) 
     { 
      if (value is Newtonsoft.Json.Linq.JObject) 
      { 
       // return (value as JObject).Properties().Any(property => property.Name == member); 

       foreach (Newtonsoft.Json.Linq.JProperty property in (value as Newtonsoft.Json.Linq.JObject).Properties()) 
       { 
        if (property.Name == member) 
         return true; 
       } 

       return false; 
      } 

      if (value is Newtonsoft.Json.Linq.JArray) 
      { 
       int index = ParseInt(member, -1); 
       return index >= 0 && index < (value as Newtonsoft.Json.Linq.JArray).Count; 
      } 
      return false; 
     } 


     public object GetMemberValue(object value, string member) 
     { 
      if (value is Newtonsoft.Json.Linq.JObject) 
      { 
       var memberValue = (value as Newtonsoft.Json.Linq.JObject)[member]; 
       return memberValue; 
      } 
      if (value is Newtonsoft.Json.Linq.JArray) 
      { 
       int index = ParseInt(member, -1); 
       return (value as Newtonsoft.Json.Linq.JArray)[index]; 
      } 
      return null; 
     } 


     public System.Collections.IEnumerable GetMembers(object value) 
     { 
      System.Collections.Generic.List<string> ls = new System.Collections.Generic.List<string>(); 

      var jobject = value as Newtonsoft.Json.Linq.JObject; 
      /// return jobject.Properties().Select(property => property.Name); 

      foreach (Newtonsoft.Json.Linq.JProperty property in jobject.Properties()) 
      { 
       ls.Add(property.Name); 
      } 

      return ls; 
     } 


     public bool IsObject(object value) 
     { 
      return value is Newtonsoft.Json.Linq.JObject; 
     } 


     public bool IsArray(object value) 
     { 
      return value is Newtonsoft.Json.Linq.JArray; 
     } 


     public bool IsPrimitive(object value) 
     { 
      if (value == null) 
       throw new System.ArgumentNullException("value"); 

      return value is Newtonsoft.Json.Linq.JObject || value is Newtonsoft.Json.Linq.JArray ? false : true; 
     } 


     private int ParseInt(string s, int defaultValue) 
     { 
      int result; 
      return int.TryParse(s, out result) ? result : defaultValue; 
     } 


    } 


} 

Usage:

object obj = Newtonsoft.Json.JsonConvert.DeserializeObject(input); 

JsonPath.JsonPathContext context = new JsonPath.JsonPathContext { ValueSystem = new JsonPath.JsonNetValueSystem() }; 

foreach (JsonPath.JsonPathNode node in context.SelectNodes(obj, "$.store.book[*].author")) 
{ 
    Console.WriteLine(node.Value); 
}