将 xml 字符串序列化为对象并序列化为 json

Serialize xml string to object and to json

我有以下 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 那么你也可以这样做:

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<string, string>();

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

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"
  }
}

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

中所述

Single child text nodes are a value directly against an element, otherwise they are accessed via #text.

因为你的 <property> 节点有一个属性,值被放在 #text 属性.

但是为什么要用Json.NET把XElement转换成ExpandoObject呢?直接使用 LINQ 进行转换很简单 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"
  }
}

演示 fiddle here.