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"
},
...
]
}
}
CodePudding user response:
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
XDocumentto 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
propertycollection 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
JObjecttostring - It stores them in the intermediate storage
JObject.FromObject(keyValueMapping)))
- It converts the
Dictionaryinto aJObject
{
"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"
}
}
CodePudding user response:
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.
