使用自定义更改将 XML 解析为 JSON
本文关键字:JSON XML 自定义 | 更新日期: 2023-09-27 18:32:34
我有一段代码可以生成"模板"文件的XML基础,所有数据都是基于当前用户从项目中动态获取的。
我需要做的是将 JSON 结构字符串发送到 API(我无法控制(。
我面临的问题是我无法使用JsonConvert.SerializeObject
从XML生成这样的JSON(格式正确的(。
在在线工具的帮助下,我从该 JSON 创建了这个 XML,JsonConvert.SerializeObject(XML)
生成一个 JSON,但相反,例如element
表示数组项 - 我需要每个项目都在[]
中,RootDTO
根元素,我根本不需要它。
因此,我需要完成的是将此XML转换为结构类似于JSON的JSON。
使用"json.net"可以吗?我需要编写"自定义服务器"吗
我拥有的 XML:
<?xml version="1.0" encoding="UTF-8"?>
<RootDTO>
<destination>
<name>companyName</name>
</destination>
<orderData>
<amount>123.45</amount>
<items>
<element>
<binding>saddle</binding>
<components>
<element>
<width>210</width>
</element>
</components>
<description>Introductory x</description>
</element>
</items>
</orderData>
</RootDTO>
生成的 JSON JsonConvert.SerializeObject
{
"?xml": {
"@version": "1.0",
"@encoding": "UTF-8"
},
"RootDTO": {
"destination": {
"name": "companyName"
},
"orderData": {
"amount": "123.45",
"items": {
"element": {
"binding": "saddle",
"components": {
"element": {
"width": "210"
}
},
"description": "Introductory x"
}
}
}
}
}
所需的 JSON
{
"destination": {
"name": "companyName"
},
"orderData": {
"amount": "123.45",
"items": [
{
"binding": "saddle",
"components": [
{
"width": "210"
}
],
"description": "Introductory x"
}
]
}
}
您有以下问题:
-
您不需要根元素。
这很容易删除,使用
JsonConvert.SerializeXNode Method(XObject, Formatting, omitRootObject = true)
或设置XmlNodeConverter.OmitRootObject = true
。 -
元素不会作为 JSON 数组返回。
XML和 JSON 之间存在基本的不一致,因为 XML 没有数组的概念。 它只有带有名称的元素序列。 那么,Json.NET 在什么情况下创建数组呢? 从在 JSON 和 XML 之间转换:
同一级别上具有相同名称的多个节点组合到一个数组中。
但是,您有一个两级列表,如下所示:
<Container> <element> </element> <!-- Repeat as necessary --> </Container>
Json.NET 不会自动将容器元素识别为数组,因此您需要使用 LINQ to XML 预处理 XML,或使用 LINQ to JSON 进行后处理。 我认为后者更容易。 幸运的是,您的所有列表条目都已命名
element
使后处理变得简单。 可以使用以下两种扩展方法完成:public static class JsonExtensions { public static JObject ToJObject(this XDocument xDoc) { // Convert to Linq to XML JObject var settings = new JsonSerializerSettings { Converters = new[] { new XmlNodeConverter { OmitRootObject = true } } }; var root = JObject.FromObject(xDoc, JsonSerializer.CreateDefault(settings)); // Convert two-level lists with "element" nodes to arrays. var groups = root.Descendants() .OfType<JProperty>() .Where(p => p.Name == "element") .GroupBy(p => (JObject)p.Parent) .Where(g => g.Key.Parent != null && g.Key.Properties().Count() == g.Count()) .ToList(); foreach (var g in groups) { // Remove values from properties to prevent cloning var values = g.Select(p => p.Value) .SelectMany(v => v.Type == JTokenType.Array ? v.Children().AsEnumerable() : new[] { v }) .ToList() .Select(v => v.RemoveFromLowestPossibleParent()); g.Key.Replace(new JArray(values)); } return root; } public static JToken RemoveFromLowestPossibleParent(this JToken node) { if (node == null) throw new ArgumentNullException("node"); var contained = node.AncestorsAndSelf().Where(t => t.Parent is JContainer && t.Parent.Type != JTokenType.Property).FirstOrDefault(); if (contained != null) contained.Remove(); // Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should if (node.Parent is JProperty) ((JProperty)node.Parent).Value = null; return node; } }
然后只需做:
var xDoc = XDocument.Parse(xmlString); var root = xDoc.ToJObject(); var jsonString = root.ToString();