【问题标题】:Binding JSON object inside of array in .NET在.NET中的数组内绑定JSON对象
【发布时间】:2016-10-23 09:08:53
【问题描述】:

我有一个来自 MarkLogic 的 JSON 响应,我将其绑定到 C# 中的模型。相关的sn-p如下:

{  
   "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&lt;string&gt;就不起作用了。

【问题讨论】:

  • JSON 无效。
  • @PaulSwetz 我修复了它,这只是返回的响应的一部分,这就是为什么我复制它时它无效

标签: c# .net json marklogic


【解决方案1】:

看起来好像 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

【讨论】:

    【解决方案2】:

    JSON 本身非常糟糕,这是我可以使用的最好的代码模型,您将不得不使用 dynamic 关键字来实际使用值数据.....顶级“值”的方式' 正在被使用并不是真正干净可解析的。就目前而言,它是一个包含 3 个项目的数组,但其中两个是字符串,其中一个是对象“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; }
    }
    

    【讨论】:

    • 我意识到这不是很好,所以希望我们能够将响应更改为更清晰的内容。如果不可能,我会尝试实施动态建议。
    • 值被定义为两个不同的东西的方式也是创建映射类时的一个问题。在一个地方它只是一个字符串,另一个地方是一个对象。
    • JSON “非常糟糕”,因为它试图表示混合内容,而 JSON 不是为这些内容而设计的。您更愿意看到 JSON 格式如何使其更容易绑定到 .NET 对象?以 XML 形式返回结果如何,它可以很好地处理混合内容?您打算如何在下游使用 sn-ps?作为 HTML,例如,在搜索结果屏幕中?将它们转换为 HTML 并在 .NET 对象中存储一个(HTML)字符串是否有意义?
    【解决方案3】:

    您发送的 JSON 与 JavaScript 兼容,因为在 JS 中,您可以在数组中包含不同类型的对象、字符串、数字等。

    但是您将values 数组声明为IEnumerable&lt;string&gt;,这意味着您发送的 JSON 中的value必须是字符串数组,您不能放置对象,因为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

    【讨论】:

    • 感谢您的回复——我正在与团队的其他成员交谈,看看我们是否可以更改 JSON。如果没有,我会看看动态方式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-10
    • 2013-11-14
    • 1970-01-01
    • 1970-01-01
    • 2013-12-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多