Amir Popovich Amir Popovich - 8 months ago 41
JSON Question

Is there anyway I can prevent the creation of an extra "object node" during converting a xml array to json using

I'm trying to convert a xml to json using

There is a problem when you try to convert between an xml and a json if you don't use some kind of schema (xsd), since you can't really identify the difference between an xml collection with a single element to a regular object.



Will be converted into:

"Drivers":{ "Driver": { "Name": "MyName" } }

since nobody tells the serializer that Drivers is a collection with a single object and it thinks it's just a regular object.
has a work around for this using the json:Array='true' tagging.

Everything works great when you tag the arrays, but it creates an extra middle object (Driver):

"Drivers": [{"Driver":{"Name": "MyName"}}]

Now I understand why this node is created, but I'm trying to find a way to bypass that creating. I would like to get this result:

"Drivers": [{"Name": "MyName"}]

Does anyone have any idea how to do something like this?

dbc dbc

Json.NET will not automatically convert a collection serialized with an outer container element (e.g., one generated with [XmlArray] attached) to a single JSON array. Instead, you will need to manually flatten the unwanted level of nesting by pre-processing the XML with LINQ-to-XML or post-processing with LINQ-to-JSON.

Since you are already preprocessing your XML to add the json:Array='true' attribute, adding some additional preprocessing would seem to be most straightforward. First, introduce the following extension method:

public static class XNodeExtensions
    /// <summary>
    /// Flatten a two-level collection with an outer container element to a one-level collection 
    /// in preparation for conversion to JSON using Json.NET
    /// </summary>
    /// <param name="parents">The outer container elements.</param>
    /// <param name="childName">The inner element name.  If null, flatten all children.</param>
    /// <param name="newChildName">The new element name.  If null, use the parent name.</param>
    public static void FlattenCollection(this IEnumerable<XElement> parents, XName childName = null, XName newChildName = null)
        if (parents == null)
            throw new ArgumentNullException();

        XNamespace json = @"";
        XName isArray = json + "Array";

        foreach (var parent in parents.ToList())
            if (parent.Parent == null)
                continue; // Removed or root
            foreach (var child in (childName == null ? parent.Elements() : parent.Elements(childName)).ToList())
                child.Name = newChildName ?? parent.Name;
                child.Add(new XAttribute(isArray, true));
            if (!parent.HasElements)

You can now do:

var xnode = XDocument.Parse(xml);
var json = JsonConvert.SerializeXNode(xnode, Formatting.Indented, true);

And get the JSON you want. Sample fiddle.

Note that <Drivers> cannot be the root element to do this, since an XML document must have exactly one root node.