2010-02-15 10 views
7

Ich versuche, JSON.NET-Framework in einem Windows-Formular zu verwenden, um einige Informationen aus einer JSON-Zeichenfolge zu lesen. Aber im Kampf um die Wörterbücher zu bekommen von dem ‚taxonomies-> Themen‘ Array und die ‚Cluster‘JSON.NET zu C# -Objekten

{ 
    "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" 
    } 
} 

Mit dem Code unten ich in der Lage, die einen Teil der Informationen zu lesen.

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:

Wie empfohlen Ich habe

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

aber wenn ich ausführen:

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

Ich bekomme die Ausnahme:

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

Update 2:

Wie schlug ich alle zusätzlichen Listen entfernt und vereinfacht die Klassen dazu:

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

ich auch hinzugefügt Testcode das Objekt wie folgt zu serialisiert:

//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); 

Zu diesem Zeitpunkt der einzige Unterschied zwischen den 2 JSON-Strings wo. die [] und Nullen für das anyString, exactString, etc. So ersetzt i die leeren eckigen Klammern für lockige Eins und es desearialized ohne Fehler :)

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

Antwort

9

Um ehrlich zu sein, ich sie nicht tun würde Weg Du machst es überhaupt. Hier ist die Art, wie ich über das Abrufen der Daten gehen würde:

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

} 

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

} 


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

Ich habe nicht die gesamte Datenklasse ausfüllen, aber Sie erhalten den Punkt. Ich habe es viel einfacher gefunden, ein Objekt in der Struktur Ihrer Eingabedaten zu erstellen und dann die DeserializeObject-Methode zum Ausfüllen der Daten zu verwenden. Dies macht den Code auch viel sauberer und ermöglicht es dem Compiler, nach Tippfehlern zu suchen.

+0

Hallo Timothy, habe ich die Frage mit den Klassen aktualisiert, wie Sie vorgeschlagen. aber ich bekomme eine Ausnahme. –

1

würde ich mit einem stark typisierte DTO-Klasse zum ersten Mal starten vorzugsweise ein Datacontract auf diese Weise Sie die Wahl bekommen wollen Sie in ein beliebiges Format serialisiert werden, das heißt JSON, XML, protobuf usw.

Hinweis: JSON eigentlich ziemlich langsam zu serialisieren/deserialisieren im Vergleich zu den meisten anderen Formaten (siehe: serialization benchmarks - JSON.NET ist "NewtonSoft.Json") Wenn Sie eine Rich-Client-App statt Web-App tun, als Sie vielleicht möchten Wählen Sie ein anderes Serialisierungsformat. Unabhängig davon, mit welchem ​​Format Sie enden, können Sie das gleiche DTO, z. Ihr Code oben würde in etwa so aussieht:

[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); 

Edit: hinzugefügt Links

Es sieht aus wie Sie Probleme mit JSON.NET in diesem Fall mit können Sie andere JSON .NET Serializer/en versuchen sollte -Serialisierer. Microsoft versendet ein System.Runtime.Serialization.Json.DataContractJsonSerializer in .NET v3.5 enthalten. Hier sind einige Hilfsklassen, die Ihnen zeigen, wie man serialize und de-serialize JSON.

Jayrock ist ein weiterer JSON-Serializer für .NET, aber es ist langsamer als der Rest und ich finde, es hat keine gute Unterstützung für Generics.

+0

Ich erhalte JSON von einem System, das ich nicht kontrollieren kann. Ich habe die Frage mit den neuen Klassen aktualisiert, aber ich bekomme eine Ausnahme. –

+0

ok, dann können Sie möglicherweise ein locker typisiertes DTO-Modell mit nur Eigenschaften von Dictionary und Liste 's machen? – mythz

+0

Können Sie mir ein Beispiel geben? Wie würde json.net wissen, auf welche Objekte es zu mappen gilt? –

2

Ja, Ihr Problem ist jetzt in der Art, wie JSON.net Objekte deserialisiert. In JSON.net wird eine C# -Klasse ein Json-Objekt. Und ein Mitglied dieser Klasse wird zu einem Schlüssel, wobei der Wert des Mitglieds zum Wert wird.

Nehmen wir das Beispiel des Taxonomy-Pfades als Beispiel. Verwenden des oben Klassendefinition JSON.net sucht JSON-Daten in diesem Format:

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

Dies nichts wie Ihre Eingabedaten aussieht.

Wenn Sie Ihre Objekte erstellen, denken Sie darüber nach.

1) Ein Basisobjekt erstellt ein {} im JSON-Code. 2) Ein Wörterbuch erstellt ein {} im JSON-Code. 3) Eine Liste erstellt a [] im json Code 4) jedes Mitglied einer Klasse einen Eintrag in dem schafft {} des json Code

Was könnte dies helfen, debuggen, damit Sie Ihre Struktur zu schaffen, Füllen Sie einige temporäre Daten aus und verwenden Sie dann JsonConvert.Serialize (myobj), um Ihnen zu zeigen, wie JSON die Struktur sieht.

Ich denke, Ihre Ausnahme kommt von vielen Klassen zu haben.

Dies ist wahrscheinlich das, was Sie der taxominies Teil des Codes soll wie folgt aussehen:

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

Warum gehst du nicht verwenden LINQ to Json?

Zum Beispiel bekommen Ihre „Art“ Knoten Ihrer Klasse zugeordnet

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

Verwandte Themen