在 C# 中用 JSON.NET 展平嵌套的 JSON
Flatten nested JSON with JSON.NET in C#
我通过具有相应层次结构的 WebApi 收到 JSON 格式的物料清单。
层级或嵌套可以是任意深度。
物料清单示例如下所示:
{
"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"
}
]
对于反序列化,我使用以下 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; }
}
此外,我使用此代码将 JSON 反序列化为一个对象:
Bom bom = JsonConvert.DeserializeObject<Bom>(File.ReadAllText(jsonPath));
反序列化原始列表,用 Enumerable.SelectMany 将其展平,然后序列化结果序列。
首先让我们定义一个映射器
JObject Map(JObject source)
{
var result = (JObject)source.DeepClone();
result.Remove("Children");
return result;
}
- 它只是克隆对象并删除
Children
属性
接下来我们定义一个递归函数来累加JObject
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);
对 accumulator
的 ToString
调用将 return 这
[
{
"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"]
});
我通过具有相应层次结构的 WebApi 收到 JSON 格式的物料清单。 层级或嵌套可以是任意深度。
物料清单示例如下所示:
{
"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"
}
]
对于反序列化,我使用以下 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; }
}
此外,我使用此代码将 JSON 反序列化为一个对象:
Bom bom = JsonConvert.DeserializeObject<Bom>(File.ReadAllText(jsonPath));
反序列化原始列表,用 Enumerable.SelectMany 将其展平,然后序列化结果序列。
首先让我们定义一个映射器
JObject Map(JObject source)
{
var result = (JObject)source.DeepClone();
result.Remove("Children");
return result;
}
- 它只是克隆对象并删除
Children
属性
接下来我们定义一个递归函数来累加JObject
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);
对 accumulator
的 ToString
调用将 return 这
[
{
"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"]
});