Reputation: 983
I have a piece of code that generate an XML base of a "template" file, all the data is dynamically taken from the project, base on current user..
And what i need to do, is to send JSON structure string to an API (i have no control on).
The problem which i am facing is that i can't manage to generate such a JSON(in the right format) from the XML using JsonConvert.SerializeObject
.
With the help of an online tool i have creates this XML from that JSON, JsonConvert.SerializeObject(XML)
generates a JSON, but instead, for example element
that represent an array item - i need each item to be in []
, RootDTO
the root element, i don't need it at all.
So what i need to accomplish is turning this XML to a JSON that structured like that JSON.
Is it possible with the use of "json.net"? Do i need to write a "custom serilizer"
The XML i have:
<?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>
The JSON JsonConvert.SerializeObject
produce
{
"?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"
}
}
}
}
}
The desired JSON
{
"destination": {
"name": "companyName"
},
"orderData": {
"amount": "123.45",
"items": [
{
"binding": "saddle",
"components": [
{
"width": "210"
}
],
"description": "Introductory x"
}
]
}
}
Upvotes: 0
Views: 2067
Reputation: 116991
You have a the following problems:
You don't want the root element.
That's easily removed, use JsonConvert.SerializeXNode Method(XObject, Formatting, omitRootObject = true)
or set XmlNodeConverter.OmitRootObject = true
.
Elements are not coming back as JSON arrays.
There is a basic inconsistency between XML and JSON in that XML does not have the concept of an array. It merely has sequences of elements with names. So, under what circumstances does Json.NET create arrays? From Converting between JSON and XML:
Multiple nodes with the same name at the same level are grouped together into an array.
However, what you have a two-level list, like so:
<Container>
<element>
</element>
<!-- Repeat as necessary -->
</Container>
Json.NET will not automatically recognize the container element as an array, thus you will need to pre-process the XML with LINQ to XML or post-process with LINQ to JSON. I think the latter is easier. Luckily, all your list entries are named element
making the post-processing straightforward. It can be done with the following two extension methods:
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;
}
}
Then just do:
var xDoc = XDocument.Parse(xmlString);
var root = xDoc.ToJObject();
var jsonString = root.ToString();
Upvotes: 1