XML to JSON - convert Json Object to Json Array

Viewed 499

In my Controller I am converting XML data to JSON like this

 var doc = new XmlDocument();
 doc.Load(xmlStream);
 doc.DocumentElement.RemoveAttribute("xmlns"); // don't want xmlns node in json

 return Json(doc.DocumentElement.ChildNodes, new JsonSerializerSettings { StringEscapeHandling = StringEscapeHandling.Default }, Encoding.UTF8);

XML looks like this

<Employees xmlns="http://company.com/schemas">
    <Employee>
        <FirstName>name1</FirstName>
        <LastName>surname1</LastName>
    <Employee>
    <Employee>
        <FirstName>name2</FirstName>
        <LastName>surname2</LastName>
    <Employee>
    <Employee>
        <FirstName>name3</FirstName>
        <LastName>surname3</LastName>
    <Employee>
</Employees>

And output JSON

[
    {
        "Employee": {
            "FirstName": "name1",
            "LastName": "surname1"
         }
    },
    {
        "Employee": {
            "FirstName": "name2",
            "LastName": "surname2"
         }
    },{
        "Employee": {
            "FirstName": "name3",
            "LastName": "surname3"
         }
    }
]

What I want to achieve

[
    {
        "FirstName": "name1",
        "LastName": "surname1"
    },
    {
        "FirstName": "name2",
        "LastName": "surname2"
    },{
        "FirstName": "name3",
        "LastName": "surname3"
    }
]

So is there any way to convert XML element to JSON array while serializing it to JSON? I want to make this dynamic, so I do not want to write entity classes while doing that.

3 Answers

I am not far what your expected output should be. I think we can do better, but here is my two lines solution:

Try it online!

var doc = XDocument.Parse(xmlData);
var json = JsonConvert.SerializeXNode(doc);

output:

{
  "Employees": {
    "@xmlns": "http://company.com/schemas",
    "Employee": [{
      "FirstName": "name1",
      "LastName": "surname1"
    }, {
      "FirstName": "name2",
      "LastName": "surname2"
    }, {
      "FirstName": "name3",
      "LastName": "surname3"
    }]
  }
}

Edit from @Peter:

Since schema is constant, it is possible to navigate the object to reach the object:

var employees = JObject.Parse(json).Children().Children().Children().ElementAt(1).Children().First();

Try it online!

It would be possible if you deserialize it in an object array before. Something like this:

    class Employee
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

    static void DoXmlToJson()
    {
        string xmlData = @"<?xml version='1.0' encoding='UTF-8'?>
                          <Employees>
                            <Employee>
                                <FirstName>name1</FirstName>
                                <LastName>surname1</LastName>
                            </Employee>
                            <Employee>
                                <FirstName>name2</FirstName>
                                <LastName>surname2</LastName>
                            </Employee>
                            <Employee>
                                <FirstName>name3</FirstName>
                                <LastName>surname3</LastName>
                            </Employee>
                        </Employees>";

        XDocument doc = XDocument.Parse(xmlData);
        var array = doc.Root.Elements()
            .Select(row => new Employee() {
                FirstName = row.Element("FirstName").Value,
                LastName = row.Element("LastName").Value
            });

        string json = JsonConvert.SerializeObject(array);

        Console.WriteLine(json);
    }

Another way with using XmlSerializer.Deserialze:

    public class Employee
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
    public class Employees
    {
        [XmlElement("Employee")]
        public Employee[] Items { get; set; }
    }

    static void DoXmlToJson()
    {
        string xmlData = @"<Employees>
                            <Employee>
                                <FirstName>name1</FirstName>
                                <LastName>surname1</LastName>
                            </Employee>
                            <Employee>
                                <FirstName>name2</FirstName>
                                //<LastName>surname2</LastName>
                            </Employee>
                            <Employee>
                                <FirstName>name3</FirstName>
                                <LastName>surname3</LastName>
                            </Employee>
                        </Employees>";


        XmlSerializer xmlSerializer = new XmlSerializer(typeof(Employees));
        MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlData));
        Employees wholeObject = (Employees)xmlSerializer.Deserialize(memoryStream);

        string json = JsonConvert.SerializeObject(wholeObject.Items);

        Console.WriteLine(json);
    }

The ouput looks in both cases like this:

[
  {
    "FirstName": "name1",
    "LastName": "surname1"
  },
  {
    "FirstName": "name2",
    "LastName": "surname2"
  },
  {
    "FirstName": "name3",
    "LastName": "surname3"
  }
]

With Cinchoo ETL - an open source library, you can do the Xml to Json easily with few lines of code

string xml = @"<Employees xmlns=""http://company.com/schemas"">
    <Employee>
        <FirstName>name1</FirstName>
        <LastName>surname1</LastName>
    </Employee>
    <Employee>
        <FirstName>name2</FirstName>
        <LastName>surname2</LastName>
    </Employee>
    <Employee>
        <FirstName>name3</FirstName>
        <LastName>surname3</LastName>
    </Employee>
</Employees>
";

StringBuilder sb = new StringBuilder();
using (var p = ChoXmlReader.LoadText(xml)
    )
{
    using (var w = new ChoJSONWriter(sb))
        w.Write(p);
}

Console.WriteLine(sb.ToString());

Output:

[
 {
  "FirstName": "name1",
  "LastName": "surname1"
 },
 {
  "FirstName": "name2",
  "LastName": "surname2"
 },
 {
  "FirstName": "name3",
  "LastName": "surname3"
 }
]

Checkout CodeProject article for some additional help.

Disclaimer: I'm the author of this library.

Related