Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert XML to JSON using C#/LINQ?

I have the following XML file that I need to convert to JSON in the server. Initially I thought I would convert it to a Dictionary and then use the JavaScriptSerializer to turn it into JSON but since each column could have a different value type, I don't think it would work. Has anyone done something similar before in C#/LINQ?

I need to preserve the Value Types(Boolean, String, Integer) of each column.

I would appreciate any advice on this as Im just starting to work with XML. Thanks.

<Columns>
 <Column Name="key1" DataType="Boolean">True</Column>
 <Column Name="key2" DataType="String">Hello World</Column>
 <Column Name="key3" DataType="Integer">999</Column>
</Columns>
like image 667
Farhad-Taran Avatar asked Aug 20 '12 11:08

Farhad-Taran


People also ask

How do I convert XML to JSON?

To convert an XML document to JSON, follow these steps: Select the XML to JSON action from the Tools > JSON Tools menu. Choose or enter the Input URL of the XML document. Choose the path of the Output file that will contain the resulting JSON document.

Can we convert XML to JSON in C#?

Once you have an XmlDocument object, you can use Json.NET to convert that object into a Json representation. var json = JsonConvert. SerializeXmlNode(doc, Formatting.

Can we convert JSON to XML?

A JSON is a lightweight data-interchange format and the format of JSON is like a key-value pair. We can convert a JSONObject into an XML format using org. json. XML class, this provides static methods to convert an XML text into a JSONObject and to convert a JSONObject into an XML text.

Can JSON be parsed by XML parser?

JSON is Unlike XML Because The biggest difference is: XML has to be parsed with an XML parser. JSON can be parsed by a standard JavaScript function.


3 Answers

using System;
using System.Linq;
using System.Web.Script.Serialization;
using System.Xml.Linq;

class Program
{
    static void Main()
    {
        var xml = 
        @"<Columns>
          <Column Name=""key1"" DataType=""Boolean"">True</Column>
          <Column Name=""key2"" DataType=""String"">Hello World</Column>
          <Column Name=""key3"" DataType=""Integer"">999</Column>
        </Columns>";
        var dic = XDocument
            .Parse(xml)
            .Descendants("Column")
            .ToDictionary(
                c => c.Attribute("Name").Value, 
                c => c.Value
            );
        var json = new JavaScriptSerializer().Serialize(dic);
        Console.WriteLine(json);
    }
}

produces:

{"key1":"True","key2":"Hello World","key3":"999"}

Obviously this treats all the values as strings. If you want to keep the underlying type semantics you could do the following:

using System;
using System.Linq;
using System.Web.Script.Serialization;
using System.Xml.Linq;

class Program
{
    static void Main()
    {
        var xml = 
        @"<Columns>
          <Column Name=""key1"" DataType=""System.Boolean"">True</Column>
          <Column Name=""key2"" DataType=""System.String"">Hello World</Column>
          <Column Name=""key3"" DataType=""System.Int32"">999</Column>
        </Columns>";
        var dic = XDocument
            .Parse(xml)
            .Descendants("Column")
            .ToDictionary(
                c => c.Attribute("Name").Value, 
                c => Convert.ChangeType(
                    c.Value,
                    typeof(string).Assembly.GetType(c.Attribute("DataType").Value, true)
                )
            );
        var json = new JavaScriptSerializer().Serialize(dic);
        Console.WriteLine(json);
    }
}

produces:

{"key1":true,"key2":"Hello World","key3":999}

And if you cannot modify the underlying XML structure you will need a custom function that will convert between your custom types and the underlying .NET type:

using System;
using System.Linq;
using System.Web.Script.Serialization;
using System.Xml.Linq;

class Program
{
    static void Main()
    {
        var xml = 
        @"<Columns>
          <Column Name=""key1"" DataType=""Boolean"">True</Column>
          <Column Name=""key2"" DataType=""String"">Hello World</Column>
          <Column Name=""key3"" DataType=""Integer"">999</Column>
        </Columns>";
        var dic = XDocument
            .Parse(xml)
            .Descendants("Column")
            .ToDictionary(
                c => c.Attribute("Name").Value, 
                c => Convert.ChangeType(
                    c.Value, 
                    GetType(c.Attribute("DataType").Value)
                )
            );
        var json = new JavaScriptSerializer().Serialize(dic);
        Console.WriteLine(json);
    }

    private static Type GetType(string type)
    {
        switch (type)
        {
            case "Integer":
                return typeof(int);
            case "String":
                return typeof(string);
            case "Boolean":
                return typeof(bool);
            // TODO: add any other types that you want to support
            default:
                throw new NotSupportedException(
                    string.Format("The type {0} is not supported", type)
                );
        }
    }
}
like image 156
Darin Dimitrov Avatar answered Nov 11 '22 07:11

Darin Dimitrov


Is it necessary to use LINQ? Otherwise you can try this:

XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
string jsonText = JsonConvert.SerializeXmlNode(doc);

Taken from this post.

like image 36
oopbase Avatar answered Nov 11 '22 09:11

oopbase


For deep nesting of XML elements with more and unknown attributes you can use this recursion:

private static string XmlToJson(string xmlString)
{
    return new JavaScriptSerializer().Serialize(GetXmlValues(XElement.Parse(xmlString)));
}

private static Dictionary<string, object> GetXmlValues(XElement xml)
{
    var attr = xml.Attributes().ToDictionary(d => d.Name.LocalName, d => (object)d.Value);
    if (xml.HasElements) attr.Add("_value", xml.Elements().Select(e => GetXmlValues(e)));
    else if (!xml.IsEmpty) attr.Add("_value", xml.Value);

    return new Dictionary<string, object> { { xml.Name.LocalName, attr } };
}

For your example the result will be:

{
    "Columns":{
        "_value":[
            {
                "Column":{
                    "Name":"key1",
                    "DataType":"Boolean",
                    "_value":"True"
                }
            },
            {
                "Column":{
                    "Name":"key2",
                    "DataType":"String",
                    "_value":"Hello World"
                }
            },
            {
                "Column":{
                    "Name":"key3",
                    "DataType":"Integer",
                    "_value":"999"
                }
            }
        ]
    }
}

And for more complex XML case like this, you can check the JSON analogue here.

like image 3
Termininja Avatar answered Nov 11 '22 07:11

Termininja