【问题标题】:Deserialize JSON string with child objects embedded in a string value反序列化带有嵌入字符串值的子对象的 JSON 字符串
【发布时间】:2019-05-14 18:33:51
【问题描述】:

我有一个 JSON 字符串,我想一口气将其反序列化为 C#。

SalesLines 的 Children 节点是一个字符串表示形式。当我反序列化时,我希望对象一直向下。使用 JSON.NET 的最佳方法是什么?

{
   "value":[
      {
         "documentType":"Quote",
         "SONumber":"S-QUO1001",
         "SalesLines":"[{\"SONumber\":\"S-QUO1001\",\"LineNum\":10000,\"ItemId\":\"1936-S\",\"ItemAttributes\":[{\"AttibuteName\":\"COLOR\",\"AttributeValue\":\"YELLOW\"},{\"AttibuteName\":\"DEPTH\",\"AttributeValue\":\"100\"},{\"AttibuteName\":\"WIDTH\",\"AttributeValue\":\"120\"},{\"AttibuteName\":\"HEIGHT\",\"AttributeValue\":\"115\"},{\"AttibuteName\":\"MATERIAL DESCRIPTION\",\"AttributeValue\":\"COTTON, WOOD LEGS\"},{\"AttibuteName\":\"MODEL YEAR\",\"AttributeValue\":\"1940\"}]}]"
      }
   ]
}

【问题讨论】:

  • 如果您的 JSON 格式正确,您可以将 EmbeddedLiteralConverter<List<SalesLine>>How do I convert an escaped JSON string within a JSON object? 应用到您的 SalesLines 属性。
  • 我已更新以包含有效的 json
  • 好的,那么将[JsonConverter(typeof(EmbeddedLiteralConverter<List<SalesLine>>)] 应用到public List<SalesLine> SalesLines { get; set; } 是否有效?
  • 为什么你有这个字符串表示,即 JSON 中的 JSON?这是一件很奇怪的事情。您是否能够更改生成此数据的代码以更好地执行此操作?那将是理想的解决方案
  • @ADyson 同意这是一个我无法控制的不幸事件。

标签: c# json json.net


【解决方案1】:

SalesLines 属性的值是双序列化 JSON:一个包含嵌入为字符串文字的 JSON 的字符串值。您希望一步将其内容反序列化为最终数据模型。

要查看数据模型的外观,您可以按如下方式对 JSON 进行转义:

var json = JToken.Parse(jsonString);

foreach(var token in json.SelectTokens("value[*].SalesLines").ToList())
{
    token.Replace(JToken.Parse((string)token));
}

Console.WriteLine(json);

然后使用 How to auto-generate a C# class file from a JSON object string 中提到的代码生成工具之一从未转义的 JSON 生成数据模型(我使用了http://json2csharp.com/):

public class ItemAttribute
{
    public string AttibuteName { get; set; }
    public string AttributeValue { get; set; }
}

public class SalesLine
{
    public string SONumber { get; set; }
    public int LineNum { get; set; }
    public string ItemId { get; set; }
    public List<ItemAttribute> ItemAttributes { get; set; }
}

public class Value
{
    public string documentType { get; set; }
    public string SONumber { get; set; }
    public List<SalesLine> SalesLines { get; set; }
}

public class RootObject
{
    public List<Value> value { get; set; }
}

最后,将EmbeddedLiteralConverter&lt;List&lt;SalesLine&gt;&gt;this answer应用到How do I convert an escaped JSON string within a JSON object?Value

public class Value
{
    public string documentType { get; set; }
    public string SONumber { get; set; }

    [JsonConverter(typeof(EmbeddedLiteralConverter<List<SalesLine>>))]
    public List<SalesLine> SalesLines { get; set; }
}

现在您可以直接将 JSON 反序列化为 RootObject

root = JsonConvert.DeserializeObject<RootObject>(jsonString);

演示小提琴here.

【讨论】:

  • 正是我想要的。谢谢!
  • 使用这个 Literal Converter 的性能是否与在循环中手动反序列化具有更高或相同的性能?
  • @aherrick - 它避免将 整个 JSON 加载到 JToken 层次结构中,因此应尽量减少内存影响。 (另外,使用dynamic 而不是JTokenRootObject 等显式类型会增加性能损失。)但您确实必须自己进行测试,请参阅ericlippert.com/2012/12/17/performance-rantstackify.com/top-11-json-performance-usage-tips,尤其是#6。
  • newtonsoft.com/json/help/html/Performance.htm#ManuallySerialize 声明 读取和写入 JSON 绝对最快的方法是直接使用 JsonTextReader/JsonTextWriter 手动序列化类型。 但是这样做很不方便,所以我不会除非万不得已,否则不推荐。
【解决方案2】:

创建一个将存储您的 SalesLines 的类,另一个将存储 ItemAttributes 的类。

SalesLines 类应该有一个属性 List。

创建一个将 List 作为属性之一的 SalesOrder 类。

那么你应该能够反序列化为 SalesOrder。

【讨论】:

  • 这并不能真正解决 OP 的问题,即 "SalesLines" 的值是一个 string 包含嵌入的 JSON 对象,他们想直接反序列化它字符串到数据模型。
  • 它确实解决了操作的问题。这个想法和你上面写的一样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-22
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多