【问题标题】:Serialize xml string to object and to json将 xml 字符串序列化为对象和 json
【发布时间】:2022-01-06 02:00:22
【问题描述】:

我有以下 xml 字符串格式,其中属性键是随机的且未知,但总是以字母数字字符开头

<properties>
  <property key="EventId">3300</property>
  <property key="source">car</property>
  <property key="type">omega</property>
  <property key="a341414">any value</property>
  <property key="arandomstring_each_time_different">any value</property>
  ....
</properties>

如何实现如下格式

{
   "properties":
   {
      "EventId": "3300", 
      "source": "car",
      ...
   }
}

我尝试了以下代码的一些变体,但没有成功

XDocument doc = XDocument.Parse(string); 
string jsonText = JsonConvert.SerializeXNode(doc);
var dynamic = JsonConvert.DeserializeObject<ExpandoObject>(jsonText);

输出

{
   "properties":{
      "property":[
         {
            "@key":"EventId",
            "#text":"3300"
         },
         {
            "@key":"source",
            "#text":"car"
         },
         ...
      ]
   }
}

【问题讨论】:

  • Json.NET 的行为如 Converting between JSON and XML 中所述:单个子文本节点是直接针对元素的值,否则它们将通过 #text 访问。 因为您的 @ 987654327@ 节点有一个属性,该值在#text 属性中。但是为什么要使用 Json.NET 将 XElement 转换为 ExpandoObject 呢?为什么不直接这样做呢? dotnetfiddle.net/JzCbWd。您的 XML 是否比您的问题中显示的更通用?
  • 谢谢你解决了我的问题,我一直在想一些图书馆会解决问题,而不是简单的解决方案。

标签: c# json .net xml json.net


【解决方案1】:

Json.NET 的行为如 Converting between JSON and XML 中所述:

单个子文本节点是直接针对元素的值,否则通过#text 访问它们。

由于您的&lt;property&gt; 节点有一个属性,因此该值被放入#text 属性中。

但是为什么要使用 Json.NET 将 XElement 转换为 ExpandoObject 呢?直接使用 LINQ to XML 进行转换很简单:

var doc = XDocument.Parse(xml);

IDictionary<string, object> properties = new ExpandoObject();
foreach (var property in doc.Root.Elements("property"))
    properties.Add(property.Attribute("key").Value, property.Value);
dynamic d = new ExpandoObject();
d.properties = properties;

根据需要导致:

{
  "properties": {
    "EventId": "3300",
    "source": "car",
    "type": "omega",
    "a341414": "any value",
    "arandomstring_each_time_different": "any value"
  }
}

演示小提琴here.

【讨论】:

    【解决方案2】:

    如果您想完全依赖 Json.Net,那么您也可以这样做:

    var docInXml = XDocument.Parse("...");
    var docInJson = JsonConvert.SerializeXNode(docInXml);
    var semiParsedJson = JObject.Parse(docInJson);
    var propertyCollection = semiParsedJson["properties"]["property"] as JArray;
    
    var keyValueMapping = new Dictionary<string, string>();
    foreach(var item in propertyCollection.Children())
    {
        keyValueMapping.Add((string)item["@key"], (string)item["#text"]);
    }
    
    var result = new JObject(new JProperty("properties", JObject.FromObject(keyValueMapping)));
    

    让我们逐行查看代码:

    var docInXml = XDocument.Parse("...");

    • 它将xml字符串解析为XDocument

    var docInJson = JsonConvert.SerializeXNode(docInXml);

    • 它将XDocument序列化为json
    {
       "properties":{
          "property":[
             {
                "@key":"EventId",
                "#text":"3300"
             },
             {
                "@key":"source",
                "#text":"car"
             },
             {
                "@key":"type",
                "#text":"omega"
             },
             {
                "@key":"a341414",
                "#text":"any value"
             },
             {
                "@key":"arandomstring_each_time_different",
                "#text":"any value"
             }
          ]
       }
    }
    

    var semiParsedJson = JObject.Parse(docInJson);

    • 它半解析 json 以便能够执行节点遍历

    var propertyCollection = semiParsedJson["properties"]["property"] as JArray;

    • 它将property 集合作为数组检索

    var keyValueMapping = new Dictionary&lt;string, string&gt;();

    • 它为关键属性和文本值定义了一个临时存储

    foreach(var item in propertyCollection.Children())

    • 它遍历数组的项目

    keyValueMapping.Add((string)item["@key"], (string)item["#text"]);

    • 它检索所需的字段并将它们从JObject 转换为string
    • 它将它们存储在中间存储中

    JObject.FromObject(keyValueMapping)))

    • 它将Dictionary 转换为JObject
    {
      "EventId": "3300",
      "source": "car",
      "type": "omega",
      "a341414": "any value",
      "arandomstring_each_time_different": "any value"
    }
    

    var result = new JObject(new JProperty("properties", ...));

    • 最后,它围绕上面创建的JObject 创建了一个包装器
    {
      "properties": {
        "EventId": "3300",
        "source": "car",
        "type": "omega",
        "a341414": "any value",
        "arandomstring_each_time_different": "any value"
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-12-31
      • 2019-02-09
      • 2015-01-29
      • 1970-01-01
      • 1970-01-01
      • 2014-01-04
      • 2020-02-03
      相关资源
      最近更新 更多