2011-09-24 22 views
15

Estoy tratando de usar JsonPath para .NET (http://code.google.com/p/jsonpath/downloads/list) y tengo problemas para encontrar un ejemplo de cómo analizar una cadena Json y una cadena JsonPath y obtener un resultado.¿Cómo usar el ejemplo de C# usando JsonPath?

¿Alguien ha usado esto?

+4

podría sugerir Json.NET como JSON alternativa analizador (http://james.newtonking.com/pages/json-net.aspx) –

+0

¿Tiene una característica similar a JsonPath? –

+3

¿Algo similar a XPath? Lo hace. Consulte la funcionalidad SelectToken de JSON.NET. Puede usar una expresión de cadena para obtener JSON. Por ejemplo: http: // stackoverflow.com/questions/1698175/what-is-the-json-net-equivilant-of-xmls-xpath-selectnodes-selectsinglenode –

Respuesta

21

El problema que está experimentando es que la versión C# de JsonPath no incluye un analizador Json, por lo que debe usarlo con otro marco Json que maneje la serialización y la deserialización.

La forma en que JsonPath funciona es utilizar una interfaz llamada IJsonPathValueSystem para recorrer objetos Json analizados. JsonPath viene con un BasicValueSystem incorporado que utiliza la interfaz IDictionary para representar los objetos Json y la interfaz IList para representar las matrices Json.

Puede crear sus propios objetos Json compatibles con BasicValueSystem construyéndolos utilizando los inicializadores de colección C#, pero esto no es de mucha utilidad cuando su Json se presenta en forma de cadenas desde un servidor remoto, por ejemplo.

Así que si solo pudiera tomar una cadena Json y analizarla en una estructura anidada de objetos IDictionary, matrices IList y valores primitivos, ¡podría utilizar JsonPath para filtrarla! Por suerte, podemos usar Json.NET que tiene buenas capacidades de serialización y deserialización para hacer esa parte del trabajo.

Desafortunadamente, Json.NET no deserializa las cadenas Json en un formato compatible con el BasicValueSystem. Por lo tanto, la primera tarea para usar JsonPath con Json.NET es escribir un JsonNetValueSystem que implemente IJsonPathValueSystem y que comprenda los objetos JObject, JArray y JValue que produce JObject.Parse.

Descargue JsonPath y Json.NET y colóquelos en un proyecto de C#. A continuación, añadir esta clase para ese proyecto:

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

Ahora con todo tres de estas piezas podemos escribir un programa de ejemplo 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(); 
    } 
} 

que produce esta salida:

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

Este ejemplo se basa en el ejemplo de JavaScript en el sitio JsonPath:

+2

En lugar de escribir una gran cantidad de código y usar dos bibliotecas, ¿no sería más fácil usar solo Json.Net como este: JObject json = JObject.Parse (@input); var values ​​= json.SelectToken ("store.book"). Valores ("autor"); –

+0

Esta respuesta responde la pregunta. Por supuesto, hay muchos otros enfoques dependiendo del problema que se resuelva. –

+0

Gracias! Exactamente lo que necesitaba. SelectToken de Json.Net no tiene la funcionalidad que necesito. –

2

Para aquellos que no les gusta 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; 
     } 


    } 


} 

Uso:

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