使用自定义更改将 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"
         }
      ]
   }
}

使用自定义更改将 XML 解析为 JSON

您有以下问题:

  1. 您不需要根元素。

    这很容易删除,使用JsonConvert.SerializeXNode Method(XObject, Formatting, omitRootObject = true)或设置XmlNodeConverter.OmitRootObject = true

  2. 元素不会作为 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();