Подтвердить что ты не робот

Как преобразовать XML в JSON с помощью С#/LINQ?

У меня есть следующий XML файл, который мне нужно преобразовать в JSON на сервере. Первоначально я думал, что буду преобразовывать его в словарь, а затем использовать JavaScriptSerializer, чтобы превратить его в JSON, но поскольку каждый столбец может иметь другой тип значения, я не думаю, что он сработает. Кто-нибудь сделал что-то подобное раньше в С#/LINQ?

Мне нужно сохранить типы значений (Boolean, String, Integer) каждого столбца.

Я был бы признателен за любые советы по этому поводу, поскольку я только начинаю работать с 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>
4b9b3361

Ответ 1

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

дает:

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

Очевидно, что это относится ко всем значениям в виде строк. Если вы хотите сохранить базовую семантику типов, вы можете сделать следующее:

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

дает:

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

И если вы не можете изменить основную структуру XML, вам понадобится настраиваемая функция, которая будет конвертировать между вашими настраиваемыми типами и базовым типом .NET:

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

Ответ 2

Нужно ли использовать LINQ? В противном случае вы можете попробовать следующее:

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

Взято из этого сообщения.

Ответ 3

Для глубокого вложения элементов XML с более и неизвестными атрибутами вы можете использовать эту рекурсию:

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

Для вашего примера результат будет:

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

И для более сложного XML-примера, такого как this, вы можете проверить аналоговый JSON .