与json.net flatten nested json在C#中

发布于 2025-01-24 13:13:23 字数 2265 浏览 2 评论 0 原文

我通过WebAPI收到JSON格式的材料清单,该WebAPI具有相应的层次结构。 层次结构或嵌套可以是任何深度。

材料清单如下所示:

{
   "Quantity":0,
   "QuantityUnit":"pcs",
   "PartNumber":"12345",
   "Parent":"",
   "Children":[
      {
         "Quantity":1,
         "QuantityUnit":"pcs",
         "PartNumber":"88774",
         "Parent":"12345",
         "Children":[
            {
               "Quantity":1,
               "QuantityUnit":"pcs",
               "PartNumber":"42447",
               "Parent":"88774"
            },
            {
               "Quantity":0.420,
               "QuantityUnit":"kg",
               "PartNumber":"12387",
               "Parent":"88774"
            }
         ]
      }
   ]
}

如何使用C#中的JSON.NET将此嵌套结构解析为一个简单的结构?

我想将其转换为:

[
   {
      "Quantity":0,
      "QuantityUnit":"pcs",
      "PartNumber":"12345",
      "Parent":""
   },
   {
      "Quantity":1,
      "QuantityUnit":"pcs",
      "PartNumber":"88774",
      "Parent":"12345"
   },
   {
      "Quantity":1,
      "QuantityUnit":"pcs",
      "PartNumber":"42447",
      "Parent":"88774"
   },
   {
      "Quantity":0.420,
      "QuantityUnit":"kg",
      "PartNumber":"12387",
      "Parent":"88774"
   }
]

对于避难所化,我使用以下类:

public class Bom
{
    public class TopLevel
    {
        public double Quantity { get; set; }
        public string QuantityUnit { get; set; }
        public string PartNumber { get; set; }
        public string Parent { get; set; }
        public List<Item> Children { get; set; }
    }

    public class Item
    {
        public double Quantity { get; set; }
        public string QuantityUnit { get; set; }
        public string PartNumber { get; set; }
        public string Parent { get; set; }
    }

    public double Quantity { get; set; }
    public string QuantityUnit { get; set; }
    public string PartNumber { get; set; }
    public string Parent { get; set; }
    public IList<TopLevel> Children { get; set; }
}

此外,我还使用此代码将JSON验证为对象:

Bom bom = JsonConvert.DeserializeObject<Bom>(File.ReadAllText(jsonPath));

I receive a bill of materials in JSON format via a WebApi, which has a corresponding hierarchy.
The hierarchy or the nesting can be any depth.

An example bill of materials is shown below:

{
   "Quantity":0,
   "QuantityUnit":"pcs",
   "PartNumber":"12345",
   "Parent":"",
   "Children":[
      {
         "Quantity":1,
         "QuantityUnit":"pcs",
         "PartNumber":"88774",
         "Parent":"12345",
         "Children":[
            {
               "Quantity":1,
               "QuantityUnit":"pcs",
               "PartNumber":"42447",
               "Parent":"88774"
            },
            {
               "Quantity":0.420,
               "QuantityUnit":"kg",
               "PartNumber":"12387",
               "Parent":"88774"
            }
         ]
      }
   ]
}

How can I resolve this nested structure into a simple structure using JSON.NET in C#?

I want to transform it to:

[
   {
      "Quantity":0,
      "QuantityUnit":"pcs",
      "PartNumber":"12345",
      "Parent":""
   },
   {
      "Quantity":1,
      "QuantityUnit":"pcs",
      "PartNumber":"88774",
      "Parent":"12345"
   },
   {
      "Quantity":1,
      "QuantityUnit":"pcs",
      "PartNumber":"42447",
      "Parent":"88774"
   },
   {
      "Quantity":0.420,
      "QuantityUnit":"kg",
      "PartNumber":"12387",
      "Parent":"88774"
   }
]

For the deserialization I use the following class:

public class Bom
{
    public class TopLevel
    {
        public double Quantity { get; set; }
        public string QuantityUnit { get; set; }
        public string PartNumber { get; set; }
        public string Parent { get; set; }
        public List<Item> Children { get; set; }
    }

    public class Item
    {
        public double Quantity { get; set; }
        public string QuantityUnit { get; set; }
        public string PartNumber { get; set; }
        public string Parent { get; set; }
    }

    public double Quantity { get; set; }
    public string QuantityUnit { get; set; }
    public string PartNumber { get; set; }
    public string Parent { get; set; }
    public IList<TopLevel> Children { get; set; }
}

Furthermore, I use this code to deserialize the JSON to an object:

Bom bom = JsonConvert.DeserializeObject<Bom>(File.ReadAllText(jsonPath));

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

记忆で 2025-01-31 13:13:23

首先,让我们定义映射器

JObject Map(JObject source)
{
    var result = (JObject)source.DeepClone();
    result.Remove("Children");
    return result;
}
  • ,它只是夹住对象并删除 children 属性

接下来,让我们定义一个递归功能以累积 jobign s

void Flatten(JArray children, JArray accumulator)
{
    if (children == null) return;
    foreach (JObject child in children)
    {
        accumulator.Add(Map(child));
        Flatten((JArray)child["Children"], accumulator);
    }
}

,最后让我们使用它们

var semiParsed = JObject.Parse(json);

var accumulator = new JArray();
accumulator.Add(Map(semiParsed));
Flatten((JArray)semiParsed["Children"], accumulator);

toString 累加器上调用将返回此

[
  {
    "Quantity": 0,
    "QuantityUnit": "pcs",
    "PartNumber": "12345",
    "Parent": ""
  },
  {
    "Quantity": 1,
    "QuantityUnit": "pcs",
    "PartNumber": "88774",
    "Parent": "12345"
  },
  {
    "Quantity": 1,
    "QuantityUnit": "pcs",
    "PartNumber": "42447",
    "Parent": "88774"
  },
  {
    "Quantity": 0.42,
    "QuantityUnit": "kg",
    "PartNumber": "12387",
    "Parent": "88774"
  }
]

更新#1

如果您的源JSON包含深层层次结构(假设超过5个级别),则 DeepClone 并不是真正有效的,因为您要复制整个子树。

要解决此问题,您只需要重写 MAP 函数

JObject Map(JObject source)
=> JObject.FromObject(new
{
    Quantity = (double)source["Quantity"],
    QuantityUnit = (string)source["QuantityUnit"],
    PartNumber = (string)source["PartNumber"],
    Parent = (string)source["Parent"]
});

First let's define a mapper

JObject Map(JObject source)
{
    var result = (JObject)source.DeepClone();
    result.Remove("Children");
    return result;
}
  • It simply clones the object and removes the Children property

Next let's define a recursive function to accumulate the JObjects

void Flatten(JArray children, JArray accumulator)
{
    if (children == null) return;
    foreach (JObject child in children)
    {
        accumulator.Add(Map(child));
        Flatten((JArray)child["Children"], accumulator);
    }
}

And finally let's make use of them

var semiParsed = JObject.Parse(json);

var accumulator = new JArray();
accumulator.Add(Map(semiParsed));
Flatten((JArray)semiParsed["Children"], accumulator);

The ToString call on the accumulator will return this

[
  {
    "Quantity": 0,
    "QuantityUnit": "pcs",
    "PartNumber": "12345",
    "Parent": ""
  },
  {
    "Quantity": 1,
    "QuantityUnit": "pcs",
    "PartNumber": "88774",
    "Parent": "12345"
  },
  {
    "Quantity": 1,
    "QuantityUnit": "pcs",
    "PartNumber": "42447",
    "Parent": "88774"
  },
  {
    "Quantity": 0.42,
    "QuantityUnit": "kg",
    "PartNumber": "12387",
    "Parent": "88774"
  }
]

UPDATE #1

If your source json contains a deep hierarchy (lets say more than 5 levels) then the DeepClone is not really efficient, since you are copying the whole subtree.

To fix this problem you just need to rewrite the Map function

JObject Map(JObject source)
=> JObject.FromObject(new
{
    Quantity = (double)source["Quantity"],
    QuantityUnit = (string)source["QuantityUnit"],
    PartNumber = (string)source["PartNumber"],
    Parent = (string)source["Parent"]
});
柒夜笙歌凉 2025-01-31 13:13:23

应对原始列表进行挑选,用 enumerable.selectmany ,并序列化结果序列。

Deserialize the original list, flatten it with Enumerable.SelectMany, and serialize the resulting sequence.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文