我有一段代码生成“模板”文件的XML库,所有数据都是根据当前用户从项目中动态获取的。
我需要做的是将JSON结构字符串发送到API(我无法控制)。
我面临的问题是我无法使用JsonConvert.SerializeObject
从XML生成这样的JSON(格式正确)。
借助在线工具,我从XML创建了这个JSON,JsonConvert.SerializeObject(XML)
生成了一个JSON,而是代表一个数组的element
item - 我需要每个项目都在[]
,RootDTO
根元素,我根本不需要它。
所以我需要完成的是将此XML转换为类似于JSON的JSON。
是否可以使用“json.net”? 我是否需要写一个“自定义serilizer”
我有的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"
}
]
}
}
答案 0 :(得分:1)
您遇到以下问题:
您不需要根元素。
可以轻松删除,使用JsonConvert.SerializeXNode Method(XObject, Formatting, omitRootObject = true)
或设置XmlNodeConverter.OmitRootObject = true
。
元素不会以JSON数组的形式返回。
XML和JSON之间存在基本的不一致,因为XML没有数组的概念。它只包含带有名称的元素序列。那么,Json.NET在什么情况下创建数组呢?来自Converting between JSON and 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();