web-dev-qa-db-fra.com

Comment convertir XML en JSON en utilisant C # / LINQ?

J'ai le fichier XML suivant que je dois convertir en JSON sur le serveur. Au départ, je pensais que je le convertirais en dictionnaire, puis utiliser JavaScriptSerializer pour le transformer en JSON, mais comme chaque colonne pourrait avoir un type de valeur différent, je ne pense pas que cela fonctionnerait. Quelqu'un a-t-il déjà fait quelque chose de similaire dans C #/LINQ?

J'ai besoin de conserver les types de valeur (booléen, chaîne, entier) de chaque colonne.

J'apprécierais tout conseil à ce sujet, car je commence tout juste à travailler avec XML. Merci.

<Columns>
 <Column Name="key1" DataType="Boolean">True</Column>
 <Column Name="key2" DataType="String">Hello World</Column>
 <Column Name="key3" DataType="Integer">999</Column>
</Columns>
22
Xerxes
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);
    }
}

produit:

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

Évidemment, cela traite toutes les valeurs comme des chaînes. Si vous souhaitez conserver la sémantique de type sous-jacente, vous pouvez procéder comme suit:

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);
    }
}

produit:

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

Et si vous ne pouvez pas modifier la structure XML sous-jacente, vous aurez besoin d'une fonction personnalisée qui convertira entre vos types personnalisés et le type .NET sous-jacent:

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)
                );
        }
    }
}
39
Darin Dimitrov

Faut-il utiliser LINQ? Sinon, vous pouvez essayer ceci:

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

Tiré de ce post .

27
oopbase

Pour une imbrication profonde d'éléments XML avec des attributs supplémentaires et inconnus, vous pouvez utiliser cette récursivité:

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 } };
}

Pour votre exemple, le résultat sera:

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

Et pour les cas XML plus complexes comme this , vous pouvez vérifier l'analogue JSON ici .

3
Termininja