2016-06-21 40 views
2

我有一个来自MarkLogic的JSON响应,我绑定到C#中的模型。相关片段是以下:在.NET中绑定数组内的JSON对象

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

我遇到的问题是与外“值”阵列,因为它包含两个串和另一个JSON对象。有没有什么办法可以在C#中绑定这个数组?我现在的模型是这样的:

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

但使用IEnumerable<string>当有数组中的对象不起作用。

+2

JSON无效。 –

+0

@PaulSwetz我修正了它,这只是返回的响应的一部分,这就是为什么当我复制它时无效 – OstrichGlue

回答

1

JSON本身非常糟糕,这是我可以使用它的最佳代码模型,您将不得不使用动态关键字来实际使用值数据......顶级“值'正在使用不是真正干净的可解析。因为它代表它是一个具有3项的数组,但他们两个都是字符串,其中之一是一个对象“亮点”

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

我意识到它不是很好,所以希望我们能够将响应改为更干净的东西如果这是不可能的,我会尝试实施动态建议。 – OstrichGlue

+0

将值定义为两种不同的东西的方式在创建映射类时也是一个问题。在一个地方,它只是一个字符串,另一个是它的一个对象。 –

+0

JSON“非常糟糕”,因为它试图表示混合内容,而JSON并不是为此设计的。您如何看待JSON格式化,使其更容易绑定到.NET对象?如何将结果恢复为XML,从而很好地处理混合内容?你打算如何使用下游代码片段?以HTML为例,在搜索结果屏幕中?将它们转换为HTML并将一个(HTML)字符串存储在.NET对象中是否合理? –

1

你发送的JSON是JavaScript的兼容,因为在JS你可以有数组中的不同类型的对象,字符串,数字等。

但是你宣布values阵列是一个IEnumerable<string>,这意味着value在JSON发送必须是一个字符串数组,你不能把一个对象,因为C#是大力类型数组。你基本上想要做的是这样的:

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

这是行不通的。

最简单的解决方案是将JSON布局更改为对C#有效。 您可以使用此:

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

    } 
}] 

添加类Markup

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

然后另一个用于Value

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

然后改变MarkLogicMatchModel

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

稍后,您可以使用String.Format将解析的标记附加到文本。 如果输入文本没有{},并且它来自您控制的组件,那么这将起作用。

如果这样不起作用,您将不得不按照Paul的建议去使用dynamic,没有其他办法。更多关于here

+0

感谢您的回复 - 我正在与我的团队的其他成员交流,看看我们是否可以更改JSON。如果没有,我会看看动态的方式。 – OstrichGlue

2

看起来好像JSON应该表示一些总体字符串中的匹配,在这种情况下,In (consolidated) enforcement actions for failure to answer subpoena, appeal from judgement for defendants.中的字符串“判断”匹配。因此,您的数据模型将需要能够重建整个字符串,并挑选出匹配的部分。

假设JSON不能被改变,我建议如下所示的数据模型:

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

使用下列转换器:

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

这里所搜索的字符串的每个部分被表示由MarkLogicMatchEntry类。普通的,不匹配的子字符串用MatchType = MatchType.Normal表示。匹配的子串用MatchType = MatchType.Highlight表示。理论上,如果需要,可以添加其他匹配类型,例如MatchType.Underline