2010-02-15 12 views
7

Sto cercando di utilizzare il framework JSON.NET in un Windows Form per leggere alcune informazioni da una stringa JSON. Ma im che lottano per ottenere i Dizionari dalla matrice 'taxonomies-> Argomenti' e il 'cluster'Oggetti da JSON.NET a C#

{ 
    "keywords": { 
     "anyString": [ 

     ], 
     "allString": { 
      "a5349f533e3aa3ccbc27de2638da38d6": "olympics" 
     }, 
     "exactString": [ 

     ], 
     "notString": [ 

     ], 
     "highlightString": [ 

     ] 
    }, 
    "dates": { 
     "startDate": "15-01-2008", 
     "endDate": "15-09-2009", 
     "useDates": true 
    }, 
    "clusters": { 
     "permission": { 
      "1": "private\/n" 
     } 
    }, 
    "taxonomies": { 
     "Topics": { 
      "2488": "Olympics 2012 (not participation)", 
      "8876": "Olympics and culture" 
     }, 
     "Keywords": { 
      "8848": "Engineering in the Olympics" 
     } 
    }, 
    "sort": { 
     "sortId": 1, 
     "sortType": 2, 
     "sort": "datetime", 
     "sortOrder": "descending" 
    } 
} 

Con il codice soffietto sono stato in grado di leggere l'alcune delle informazioni.

JObject searchCriteria = JObject.Parse(contentSearchCriteria); 
//search criteria 
IEnumerable<string> allString = searchCriteria["keywords"]["allString"].Children().Values<string>(); 
IEnumerable<string> anyString = searchCriteria["keywords"]["anyString"].Children().Values<string>(); 
IEnumerable<string> notString = searchCriteria["keywords"]["notString"].Children().Values<string>(); 
IEnumerable<string> exactString = searchCriteria["keywords"]["exactString"].Children().Values<string>(); 
IEnumerable<string> highlightString = searchCriteria["keywords"]["highlightString"].Children().Values<string>(); 
//dates 
string startDate = (string)searchCriteria["dates"]["startDate"]; 
string endDate = (string)searchCriteria["dates"]["endDate"]; 
bool useDates = (bool)searchCriteria["dates"]["useDates"]; 

//sort 
int sortId = (int)searchCriteria["sort"]["sortId"]; 
int sortType = (int)searchCriteria["sort"]["sortType"]; 
string sort = (string)searchCriteria["sort"]["sort"]; 
string sortOrder = (string)searchCriteria["sort"]["sortOrder"]; 

UPDATE:

come consigliato ho aggiunto

class SMSearchCriteria 
    { 
     public SMKeywords keywords { get; set; } 
     public SMDates dates { get; set; } 
     public SMClusters clusters { get; set; } 
     public SMTaxonomies taxonomies { get; set; } 
     public SMSort sort { get; set; } 
    } 

    class SMKeywords 
    { 
     public List<Dictionary<string, string>> AnyString {get; set;} 
     public List<Dictionary<string, string>> AllString { get; set; } 
     public List<Dictionary<string, string>> ExactString { get; set; } 
     public List<Dictionary<string, string>> NotString { get; set; } 
     public List<Dictionary<string, string>> HighlightString { get; set; } 
    } 

    class SMDates 
    { 
     public string startDate { get; set; } 
     public string endDate { get; set; } 
     public bool useDates { get; set; } 
    } 

    class SMClusters 
    { 
     List<SMCluster> cluster; 
    } 

    class SMCluster 
    { 
     public Dictionary<string, string> cluster { get; set; } 
    } 

    class SMTaxonomies 
    { 
     public List<SMTaxonomy> taxonomies { get; set; } 
    } 

    class SMTaxonomy 
    { 
     public Dictionary<string, List<SMCategory>> taxonomy { get; set; } 
    } 

    class SMCategory 
    { 
     public Dictionary<int, string> category { get; set; } 
    } 

    class SMSort 
    { 
     public int sortId { get; set; } 
     public int sortType { get; set; } 
     public string sort { get; set; } 
     public string sortOrder { get; set; } 
    } 

ma quando eseguo:

var mydata = JsonConvert.DeserializeObject<SMSearchCriteria>(contentSearchCriteria); 

ottengo l'eccezione:

[Newtonsoft.Json.JsonSerializationException] = {"Cannot deserialize JSON object into type 'System.Collections.Generic.List`1[System.Collections.Generic.Dictionary`2[System.String,System.String]]'."} 

Aggiornamento 2:

Come suggerito Ho rimosso tutte le liste extra e semplificato le Classi a questo:

class SearchMasterSearchCriteria 
    { 
     public SMKeywords keywords { get; set; } 
     public SMDates dates { get; set; } 
     public Dictionary<string, Dictionary<int, string>> clusters { get; set; } 
     public Dictionary<string, Dictionary<int, string>> taxonomies { get; set; } 
     public SMSort sort { get; set; } 
    } 

    class SMKeywords 
    { 
     public Dictionary<string, string> anyString {get; set;} 
     public Dictionary<string, string> allString { get; set; } 
     public Dictionary<string, string> exactString { get; set; } 
     public Dictionary<string, string> notString { get; set; } 
     public Dictionary<string, string> highlightString { get; set; } 
    } 

    class SMDates 
    { 
     public string startDate { get; set; } 
     public string endDate { get; set; } 
     public bool useDates { get; set; } 
    } 

    class SMSort 
    { 
     public int sortId { get; set; } 
     public int sortType { get; set; } 
     public string sort { get; set; } 
     public string sortOrder { get; set; } 
    } 

ho codice di prova aggiunto anche per serializzare l'oggetto in questo modo:

//criteria 
      SearchMasterSearchCriteria smCriteria = new SearchMasterSearchCriteria(); 

      //keywords 
      SMKeywords smKeywords = new SMKeywords(); ; 
      Dictionary<string, string> dict = new Dictionary<string, string>(); 
      dict.Add("a5349f533e3aa3ccbc27de2638da38d6", "olympics"); 
      dict.Add("9cfa7aefcc61936b70aaec6729329eda", "games"); 
      smKeywords.allString = dict; 

      //category 
      Dictionary<int, string> categorieDict = new Dictionary<int, string>(); 
      categorieDict.Add(2488, "Olympics 2012 (not participation)"); 
      categorieDict.Add(8876, "Olympics and culture"); 

      //taxonomies 
      Dictionary<string, Dictionary<int, string>> taxonomiesDict = new Dictionary<string, Dictionary<int, string>>(); 
      taxonomiesDict.Add("Topics", categorieDict); 

      //metadata 
      Dictionary<int, string> metadataDict = new Dictionary<int, string>(); 
      metadataDict.Add(1, @"private/n"); 

      //clusters 
      Dictionary<string, Dictionary<int, string>> clustersDict = new Dictionary<string, Dictionary<int, string>>(); 
      clustersDict.Add("permission", metadataDict); 


      //dates 
      SMDates smDates = new SMDates(); 
      smDates.startDate = "15-01-2008"; 
      smDates.endDate = "15-09-2009"; 
      smDates.useDates = true; 

      //sort 
      SMSort smSort = new SMSort(); 
      smSort.sortId = 1; 
      smSort.sortType = 2; 
      smSort.sort = "datetime"; 
      smSort.sortOrder = "descending"; 

      //add to criteria. 
      smCriteria.keywords = smKeywords; 
      smCriteria.clusters = clustersDict; 
      smCriteria.taxonomies = taxonomiesDict; 
      smCriteria.dates = smDates; 
      smCriteria.sort = smSort; 

      //serialize 
      string json = JsonConvert.SerializeObject(smCriteria); 
      var mydata1 = JsonConvert.DeserializeObject<SearchMasterSearchCriteria>(json); 

A quell'ora l'unica differenza tra le 2 stringhe json dove. [] e nulli per l'anyString, exactString, ecc Così ho sostituito le parentesi quadre vuote per quelle graffe e desearialized senza errori :)

contentSearchCriteria = contentSearchCriteria.Replace("[]", "{}"); 
var mydata = JsonConvert.DeserializeObject<SearchMasterSearchCriteria>(contentSearchCriteria); 

risposta

9

Per essere onesto con te io non lo farei loro modo lo stai facendo affatto. Ecco il modo in cui mi piacerebbe andare sul recupero dei dati:

class Data { 
    Dictionary<string, Dictionary<string, string>> keywords; 
    DatesClass dates; 
    ....... 

} 

class DatesClass 
{ 
    string startDate; 
    string endDate; 
    bool? useDates 

} 


var mydata = JsonConvert.DeserializeObject<Data>(jsonstring); 

Non ho compilare l'intera classe di dati, ma si ottiene il punto. Ho trovato molto più facile creare un oggetto nella struttura dei dati di input e quindi utilizzare il metodo DeserializeObject per compilare i dati. Ciò rende anche il codice molto più pulito e consente al compilatore di controllare gli errori di battitura.

+0

Ciao Timothy, ho aggiornato la questione con le classi come lei ha suggerito. ma sto ottenendo un'eccezione –

1

Vorrei iniziare con un fortemente tipizzato dto prima classe preferibilmente un DataContract in questo modo si ottiene la possibilità di serializzare in qualsiasi formato che si desidera, ad esempio JSON, XML, protobuf, ecc

Nota: JSON è in realtà piuttosto lento per serializzare/de-serializzare rispetto alla maggior parte degli altri formati (vedi: serialization benchmarks - JSON.NET è 'NewtonSoft.Json') Se si sta facendo un'app client ricca invece di app web di quanto si desideri scegli un diverso formato di serializzazione. Indipendentemente dal formato in cui ti trovi, puoi comunque riutilizzare lo stesso DTO, ad es. il codice di cui sopra sarebbe simile a:

[DataContract] 
public class MyDto 
{ 
    [DataMember] 
    public Keywords keywords { get; set; } 
} 

[DataContract] 
public class Keywords 
{ 
    [DataMember] 
    public List<string> anyString { get; set; } 

    [DataMember] 
    public Dictionary<string,string> allString { get; set; } 

    [DataMember] 
    public List<string> exactString { get; set; } 

    [DataMember] 
    public List<string> notString { get; set; } 

    [DataMember] 
    public List<string> highlightString { get; set; } 
} 

var dto = new MyDto { Keywords = { allString = {{"a5349f533e3aa3ccbc27de2638da38d6", "olympics"}} }; 

var json = JsonConvert.SerializeObject(dto); 
var fromJson = JsonConvert.DeserializeObject<MyDto>(json); 

Modifica: link aggiunti

Sembra che si può essere problemi con JSON.NET nel qual caso si dovrebbe provare altri serializzatori JSON .NET/de -serializers. Microsoft spedisce un sistema.Runtime.Serialization.Json.DataContractJsonSerializer incluso in .NET v3.5. Ecco alcune classi di supporto che mostrano come utilizzare serialize e de-serialize JSON.

Jayrock è un altro serializzatore JSON per .NET ma è più lento del resto e trovo che non abbia un buon supporto per Generics.

+0

Ricevo quel JSON da un sistema che non ho il controllo. Ho aggiornato la domanda con le nuove classi, ma sto ottenendo un'eccezione. –

+0

ok, allora potresti essere in grado di creare un modello DTO generico con le sole proprietà del dizionario e List ? – mythz

+0

Potrebbe farmi un esempio? in che modo json.net sa a quali proprietà mappare? –

2

Sì, il problema ora è nel modo in cui JSON.net deserializza gli oggetti. In JSON.net una classe C# diventa un oggetto Json. E un membro di quella classe diventa una chiave con il valore del membro che diventa il valore.

Prendiamo come esempio l'esempio del percorso Tassonomia. Usando il vostro definizione di classe sopra JSON.net è alla ricerca di dati JSON in questo formato:

{"taxonomies": {"taxonomies":[{"taxonomy": {"Topics": {1212, "foo"}}}]} 

Questo sembra niente affatto come i dati di input.

Quando crei i tuoi oggetti, pensa in questo modo.

1) Un oggetto di base crea un {} nel codice JSON. 2) Un dizionario crea un {} nel codice JSON. 3) un elenco crea un [] nel codice JSON 4) ogni membro di una classe crea una voce nella {} del codice JSON

cosa potrebbe aiutare a eseguire il debug di questo per voi è quello di creare la struttura, riempire alcuni dati temporanei quindi utilizzare JsonConvert.Serialize (myobj) per mostrare quale JSON pensa che la struttura sarà simile.

Penso che la tua eccezione derivi dall'avere accesso a molte classi.

questo è probabilmente quello che si vuole la parte taxominies del codice per assomigliare:

class SMSearchCriteria 
{ 
     public SMKeywords keywords { get; set; } 
     public SMDates dates { get; set; } 
     public SMClusters clusters { get; set; } 
     public SMTaxominies taxonomies { get; set; } 
     public SMSort sort { get; set; } 
} 

class SMTaxominies 
{ 
    public Dictionary<string, string> Topics; 
    public Keywords<string, string> Keywords; 
} 
0

Perché non utilizzare LINQ a JSON?

Per esempio, ottenendo i nodi "sort" mappati alla classe

var jsonResult = JObject.Parse(jsonString); 

var sortItem = from s in jsonResult["sort"] 
select new MySortObject{ 
          SortId = s.Value<int>("sortId") 
         }; 

http://www.newtonsoft.com/json/help/html/QueryJsonLinq.htm

Problemi correlati