2016-06-21 7 views
2

Ich habe eine JSON-Antwort von MarkLogic, die ich an ein Modell in C# binde. Der entsprechende Code-Schnipsel ist unten:Bindung von JSON-Objekten innerhalb von Arrays in .NET

{ 
    "snippets":{ 
     "match":[ 
     { 
      "value":[ 
       "In (consolidated) enforcement actions for failure to answer subpoena, appeal from ", 
       { 
        "highlight":{ 
        "value":"judgement" 
        } 
       }, 
       " for defendants." 
      ] 
     } 
     ] 
    } 
} 

Das Problem, das ich habe, ist, mit dem äußeren „Wert“ Array, da es zwei Strings enthält und eine anderes JSON-Objekt. Gibt es eine Möglichkeit, dieses Array in C# zu binden? Meine aktuelle Modelle wie folgt aussehen:

[JsonProperty(PropertyName = "snippets")] 
public MarkLogicSnippetsModel Snippets { get; set; } 

public class MarkLogicSnippetsModel 
{ 
    [JsonProperty(PropertyName = "match")] 
    public IEnumerable<MarkLogicMatchModel> Matches { get; set; } 
} 

public class MarkLogicMatchModel 
{ 
    [JsonProperty(PropertyName = "value")] 
    public IEnumerable<string> Values { get; set; } 
} 

Aber IEnumerable<string> mit funktioniert nicht, wenn sich ein Objekt in dem Array.

+2

Der JSON ist nicht gültig. –

+0

@PaulSwetz Ich habe es behoben, das ist nur ein Teil der Antwort, die zurückgegeben wird, weshalb es nicht gültig war, als ich es kopierte – OstrichGlue

Antwort

1

Die JSON selbst ist ziemlich schrecklich, das ist das beste Code-Modell, das ich damit arbeiten könnte, müssen Sie das dynamische Schlüsselwort verwenden, um die Wertdaten tatsächlich zu verwenden ..... die Art und Weise die oberste Ebene ' Wert 'verwendet wird, ist nicht wirklich sauber parsbar. Wie es aussieht es ein Array ist, die 3 Elemente hat, aber zwei von ihnen sind Strings und einer von ihnen ist ein Objekt ‚Highlight‘

public class Match 
{ 
    public List<object> value { get; set; } 
} 

public class Snippets 
{ 
    public List<Match> match { get; set; } 
} 

public class RootObject 
{ 
    public Snippets snippets { get; set; } 
} 
+0

Ich weiß, es ist nicht großartig, also hoffentlich können wir die Antwort in ändern etwas sauberer. Ich werde versuchen, den dynamischen Vorschlag zu implementieren, wenn das nicht möglich ist. – OstrichGlue

+0

Der Weg Wert ist als zwei verschiedene Dinge definiert ist auch ein Problem beim Erstellen der Mapping-Klassen. An einer Stelle ist es nur eine Schnur und die andere ist ein Objekt. –

+0

Der JSON ist "ziemlich schrecklich", weil er versucht, gemischten Content darzustellen, für den JSON nicht gedacht war. Wie würden Sie das JSON formatiert sehen, um das Binden an .NET-Objekte zu erleichtern? Wie wäre es, die Ergebnisse als XML zurückzubekommen, das gemischte Inhalte gut verarbeitet? Wie planen Sie, die Snippets downstream zu verwenden? B. HTML, in einem Suchergebnisbildschirm? Wäre es sinnvoll, sie in HTML umzuwandeln und nur eine Zeichenfolge (von HTML) im .NET-Objekt zu speichern? –

1

Die JSON Sie senden ist JavaScript kompatibel, da in JS können Sie verschiedene Arten von Objekten, Strings, Zahlen usw. in einem Array.

Aber Sie erklärte die values Array ein IEnumerable<string> zu sein, die value im JSON bedeutet, dass Sie müssen sein ein Array von Strings senden, können Sie ein Objekt nicht gesetzt, weil C# Arrays stark typisiert ist, wird. Was Sie im Grunde versuchen zu tun ist das:

List<string> strings = new List<string>(); 
strings.Add("123"); 
strings.Add(new { foo: "foo" }); 

Das wird nicht funktionieren.

Die einfachste Lösung besteht darin, das JSON-Layout so zu ändern, dass es für C# gültig ist. könnten Sie verwenden:

"match": [{ 
    "value": { 
     "text": "In (consolidated) enforcement actions for failure to answer subpoena, appeal from {0} for defendants.", 
     "markup": [{ 
      "type": "highlight", 
      "value" : "judgement" 
     }] 

    } 
}] 

eine Klasse hinzufügen für Markup

public class Markup 
{ 
    [JsonProperty(PropertyName = "type")] 
    public string Type { get; set; } 
    [JsonProperty(PropertyName = "value")] 
    public string Value {get; set; } 
} 

Dann eine weitere für Value

public class Value 
{ 
    [JsonProperty(PropertyName = "text")] 
    public string Text{ get; set; } 
    [JsonProperty(PropertyName = "markup")] 
    public IEnumerable<Markup> Markup {get; set; } 
} 

Dann MarkLogicMatchModel ändern

public class MarkLogicMatchModel 
{ 
    [JsonProperty(PropertyName = "value")] 
    public IEnumerable<Value> Values { get; set; } 
} 

Später könnten Sie String.Format verwenden, um das analysierte Markup an den Text anzuhängen. Dies funktioniert, wenn der eingegebene Text nicht { oder } hat, und wenn es von einer Komponente stammt, die Sie natürlich steuern.

Wenn das nicht funktioniert, müssen Sie gehen dynamic wie Paul vorgeschlagen, keine andere Möglichkeit. Mehr zu diesem here

+0

Danke für die Antwort - Ich spreche mit den anderen Mitgliedern meines Teams, um zu sehen, ob wir den JSON ändern können. Wenn nicht, schaue ich mir den dynamischen Weg an. – OstrichGlue

2

Es sieht aus, als ob die JSON soll Matches in einigen Gesamt Zeichenfolge darzustellen, in diesem Fall eine Übereinstimmung der Zeichenfolge „Urteil“ in In (consolidated) enforcement actions for failure to answer subpoena, appeal from judgement for defendants. So wird Ihr Datenmodell in der Lage sein zu müssen gehen rekonstruieren Sie die gesamte Saite und wählen Sie den passenden Teil aus.

Unter der Annahme, die JSON kann nicht geändert werden, würde ich ein Datenmodell wie die folgende vorschlagen:

public class RootObject 
{ 
    [JsonProperty(PropertyName = "snippets")] 
    public MarkLogicSnippetsModel Snippets { get; set; } 
} 

public class MarkLogicSnippetsModel 
{ 
    [JsonProperty(PropertyName = "match")] 
    public IEnumerable<MarkLogicMatchModel> Matches { get; set; } 
} 

public class MarkLogicMatchModel 
{ 
    [JsonProperty(PropertyName = "value")] 
    public List<MarkLogicMatchEntry> Values { get; set; } 
} 

public enum MatchType 
{ 
    Normal, 
    Highlight, 
} 

[JsonConverter(typeof(MarkLogicMatchEntryConverter))] 
public class MarkLogicMatchEntry 
{ 
    public MatchType MatchType { get; set; } 

    public string Value { get; set; } 
} 

Unter Verwendung der folgenden Konverter:

class MarkLogicMatchEntryConverter : JsonConverter 
{ 
    JsonSerializer GetEnumSerializer() 
    { 
     return JsonSerializer.CreateDefault(new JsonSerializerSettings { Converters = new[] { new StringEnumConverter { CamelCaseText = true } } }); 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(MarkLogicMatchEntry); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.Null) 
      return null; 
     else if (reader.TokenType == JsonToken.String) 
     { 
      return new MarkLogicMatchEntry { MatchType = MatchType.Normal, Value = reader.Value.ToString() }; 
     } 
     else 
     { 
      var obj = JObject.Load(reader); 
      var property = obj.Properties().FirstOrDefault(); 
      var type = ((JValue)property.Name).ToObject<MatchType>(GetEnumSerializer()); 
      var value = (string)property.Value.SelectToken("value"); 

      return new MarkLogicMatchEntry { MatchType = type, Value = value }; 
     } 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var match = (MarkLogicMatchEntry)value; 
     if (match.MatchType == MatchType.Normal) 
     { 
      writer.WriteValue(match.Value); 
     } 
     else 
     { 
      var propertyName = (string)JToken.FromObject(match.MatchType, GetEnumSerializer()); 
      var obj = new JObject(new JProperty(propertyName, new JObject(new JProperty("value", match.Value)))); 
      obj.WriteTo(writer); 
     } 
    } 
} 

Hier wird jeder Abschnitt der gesuchten Zeichenfolge dargestellt wird von einer MarkLogicMatchEntry Klasse. Normale, nicht übereinstimmende Teilstrings werden mit MatchType = MatchType.Normal dargestellt. Übereinstimmende Teilstrings werden mit MatchType = MatchType.Highlight dargestellt. Theoretisch könnten andere Übereinstimmungstypen wie MatchType.Underline hinzugefügt werden, falls erforderlich.

Verwandte Themen