JSON.Net Xml Serialization misunderstands arrays
Giving my +1 to Iván Pérez Gómez and providing some code here to support his answer:
Add the required json.net namespace to the root node:
private static void AddJsonNetRootAttribute(XmlDocument xmlD)
{
XmlAttribute jsonNS = xmlD.CreateAttribute("xmlns", "json", "http://www.w3.org/2000/xmlns/");
jsonNS.Value = "http://james.newtonking.com/projects/json";
xmlD.DocumentElement.SetAttributeNode(jsonNS);
}
And to add json:Array attribute to elements found by xpath:
private static void AddJsonArrayAttributesForXPath(string xpath, XmlDocument doc)
{
var elements = doc.SelectNodes(xpath);
foreach (var element in elements)
{
var el = element as XmlElement;
if (el != null)
{
var jsonArray = doc.CreateAttribute("json", "Array", "http://james.newtonking.com/projects/json");
jsonArray.Value = "true";
el.SetAttributeNode(jsonArray);
}
}
}
Here is a sample of a single child node as a json array:
I did fix this behavior like this
// Handle JsonConvert array bug
var rows = doc.SelectNodes("//Row");
if(rows.Count == 1)
{
var contentNode = doc.SelectSingleNode("//List/Content");
contentNode.AppendChild(doc.CreateNode("element", "Row", ""));
// Convert to JSON and replace the empty element we created but keep the array declaration
returnJson = JsonConvert.SerializeXmlNode(doc).Replace(",null]", "]");
}
else
{
// Convert to JSON
returnJson = JsonConvert.SerializeXmlNode(doc);
}
It's a bit dirty but it works. I'm still interested in other solutions!
From Json.NET documentation: http://james.newtonking.com/projects/json/help/?topic=html/ConvertingJSONandXML.htm
You can force a node to be rendered as an Array by adding the attribute json:Array='true'
to the XML node you are converting to JSON. Also, you need to declare the json prefix namespace at the XML header xmlns:json='http://james.newtonking.com/projects/json'
or else you will get an XML error stating that the json prefix is not declared.
The next example is provided by the documentation:
xml = @"<person xmlns:json='http://james.newtonking.com/projects/json' id='1'>
<name>Alan</name>
<url>http://www.google.com</url>
<role json:Array='true'>Admin</role>
</person>";
Generated output:
{
"person": {
"@id": "1",
"name": "Alan",
"url": "http://www.google.com",
"role": [
"Admin"
]
}
}