简体   繁体   中英

Serialize xml string to object and to json

I have following xml string format where property key is random and not known but always start with alphanumeric character

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

how to achieve following format

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

I tried some variation of following code, but with no luck

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

output

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

If you want to purely rely on Json.Net then you can do that as well:

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)));

Let's see the code line-by-line:

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

  • It parses the xml string as XDocument

var docInJson = JsonConvert.SerializeXNode(docInXml);

  • It serializes the XDocument to 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);

  • It semi parses the json to be able to perform node traversal

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

  • It retrieves the property collection as an array

var keyValueMapping = new Dictionary<string, string>();

  • It defines a temporary storage for the key attributes and text values

foreach(var item in propertyCollection.Children())

  • It iterates through the array's items

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

  • It retrieves the desired fields and converts them from JObject to string
  • It stores them in the intermediate storage

JObject.FromObject(keyValueMapping)))

  • It converts the Dictionary into a JObject
{
  "EventId": "3300",
  "source": "car",
  "type": "omega",
  "a341414": "any value",
  "arandomstring_each_time_different": "any value"
}

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

  • Finally, it creates a wrapper around the above created JObject
{
  "properties": {
    "EventId": "3300",
    "source": "car",
    "type": "omega",
    "a341414": "any value",
    "arandomstring_each_time_different": "any value"
  }
}

Json.NET is behaving as documented in Converting between JSON and XML :

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

Since your <property> nodes have an attribute, the value is placed into in a #text property.

But why use Json.NET to convert from XElement to ExpandoObject ? It's simple enough to do the conversion directly using 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;

Which results in, as required:

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

Demo fiddle here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM