Преобразовать строку XML в объект

126

Я получаю XML-строки над сокетом и хотел бы преобразовать их в объекты С#.

Сообщения имеют форму:

<msg>
   <id>1</id>
   <action>stop</action>
</msg>

Я новичок в .Net, и я не уверен в лучшей практике для этого. Раньше я использовал JAXB для Java и не был уверен, есть ли что-то подобное, или если это будет обрабатываться по-другому.

Показать ещё 1 комментарий
Теги:
xml-parsing
xml-serialization

11 ответов

211
Лучший ответ

Вам нужно использовать инструмент xsd.exe, который устанавливается с SDK Windows в каталог, похожий на:

C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin

И на 64-битных компьютерах:

C:\Program Files (x86)\Microsoft SDKs\Windows\v6.0A\bin

И на компьютерах с Windows 10:

C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin

В первом запуске вы используете xsd.exe, и вы конвертируете образец XML в файл XSD (файл XML-схемы):

xsd yourfile.xml

Это дает вам yourfile.xsd, который на втором этапе можно снова преобразовать с помощью xsd.exe в класс С#:

xsd yourfile.xsd /c

Это должно дать вам файл yourfile.cs, который будет содержать класс С#, который вы можете использовать для десериализации XML файла, который вы получаете, например:

XmlSerializer serializer = new XmlSerializer(typeof(msg));
msg resultingMessage = (msg)serializer.Deserialize(new XmlTextReader("yourfile.xml"));

В большинстве случаев это работает очень хорошо.

Обновление: XML-сериализатор примет любой поток в качестве своего ввода - либо файл, либо поток памяти будут в порядке:

XmlSerializer serializer = new XmlSerializer(typeof(msg));
MemoryStream memStream = new MemoryStream(Encoding.UTF8.GetBytes(inputString));
msg resultingMessage = (msg)serializer.Deserialize(memStream);

или используйте StringReader:

XmlSerializer serializer = new XmlSerializer(typeof(msg));
StringReader rdr = new StringReader(inputString);
msg resultingMessage = (msg)serializer.Deserialize(rdr);
  • 0
    Спасибо за подробное объяснение. В моем случае XML идет через сокет и является строкой. Как бы я десериализовал строку вместо файла XML?
  • 5
    @Steve: Вы можете открыть StringReader и передать метод Deserialize. StringReader является производным от TextReader.
Показать ещё 10 комментариев
178

У вас есть две возможности.

Метод 1. Инструмент XSD


Предположим, что у вас есть ваш XML файл в этом месте C:\path\to\xml\file.xml
  • Откройте Командная строка разработчика
    Вы можете найти его в Start Menu > Programs > Microsoft Visual Studio 2012 > Visual Studio Tools Или, если у вас есть Windows 8, можно просто начать набирать Командная строка разработчика на экране запуска
  • Измените местоположение в каталоге файла XML, набрав cd /D "C:\path\to\xml"
  • Создайте XSD файл из вашего xml файла, набрав xsd file.xml
  • Создайте классы С#, набрав xsd /c file.xsd

И это! Вы создали классы С# из XML файла в C:\path\to\xml\file.cs

Способ 2 - Вставить специальный


Требуемая Visual Studio 2012+ с .Net Framework >= 4.5 как цель проекта
  • Скопировать содержимое вашего XML файла в буфер обмена
  • Добавьте к вашему решению новый пустой файл класса (Shift + Alt + C)
  • Откройте этот файл и в меню нажмите Edit > Paste special > Paste XML As Classes
    Изображение 1096

И это!

Использование


Использование этого класса-помощника очень просто:

using System;
using System.IO;
using System.Web.Script.Serialization; // Add reference: System.Web.Extensions
using System.Xml;
using System.Xml.Serialization;

namespace Helpers
{
    internal static class ParseHelpers
    {
        private static JavaScriptSerializer json;
        private static JavaScriptSerializer JSON { get { return json ?? (json = new JavaScriptSerializer()); } }

        public static Stream ToStream(this string @this)
        {
            var stream = new MemoryStream();
            var writer = new StreamWriter(stream);
            writer.Write(@this);
            writer.Flush();
            stream.Position = 0;
            return stream;
        }


        public static T ParseXML<T>(this string @this) where T : class
        {
            var reader = XmlReader.Create(@this.Trim().ToStream(), new XmlReaderSettings() { ConformanceLevel = ConformanceLevel.Document });
            return new XmlSerializer(typeof(T)).Deserialize(reader) as T;
        }

        public static T ParseJSON<T>(this string @this) where T : class
        {
            return JSON.Deserialize<T>(@this.Trim());
        }
    }
}

Все, что вам нужно сделать сейчас, это:

    public class JSONRoot
    {
        public catalog catalog { get; set; }
    }
    // ...

    string xml = File.ReadAllText(@"D:\file.xml");
    var catalog1 = xml.ParseXML<catalog>();

    string json = File.ReadAllText(@"D:\file.json");
    var catalog2 = json.ParseJSON<JSONRoot>();
  • 7
    веселит. В отношении метода 2 вам нужно настроить таргетинг на .net 4.5, иначе опция недоступна.
  • 0
    О пасте особый метод. Почему он доступен только в FW4.5? Смогу ли я использовать сгенерированный класс в проекте FW4.0 или он не будет работать?
Показать ещё 6 комментариев
39

Попробуйте этот метод для преобразования Xml в объект. Это сделано именно для того, что вы делаете:

protected T FromXml<T>(String xml)
{
    T returnedXmlClass = default(T);

    try
    {
        using (TextReader reader = new StringReader(xml))
        {
            try
            {
                returnedXmlClass = 
                    (T)new XmlSerializer(typeof(T)).Deserialize(reader);
            }
            catch (InvalidOperationException)
            {
                // String passed is not XML, simply return defaultXmlClass
            }
        }
    }
    catch (Exception ex)
    {
    }

    return returnedXmlClass ;        
}

Назовите его с помощью этого кода:

YourStrongTypedEntity entity = FromXml<YourStrongTypedEntity>(YourMsgString);
  • 5
    Получил эту ошибку xmlns = ''> не ожидал. "}, Любая идея?
  • 0
    Проблема в том, что вам нужно заранее сформировать свой класс. Может быть, функция, которая выводит класс при заданном XML? xsd.exe является хитом и промахом (в основном скучаю по сложным вещам) ...
Показать ещё 1 комментарий
7

Просто запустите Visual Studio 2013 в качестве администратора... Скопируйте содержимое вашего файла Xml. Перейти к Visual Studio 2013 > Edit > Paste Special > Вставить Xml как классы С# Он создаст ваши классы С# в соответствии с вашим содержимым файла Xml.

5

На всякий случай кто-то может найти это полезным:

public static class XmlConvert
{
    public static string SerializeObject<T>(T dataObject)
    {
        if (dataObject == null)
        {
            return string.Empty;
        }
        try
        {
            using (StringWriter stringWriter = new System.IO.StringWriter())
            {
                var serializer = new XmlSerializer(typeof(T));
                serializer.Serialize(stringWriter, dataObject);
                return stringWriter.ToString();
            }
        }
        catch (Exception ex)
        {
            return string.Empty;
        }
    }

    public static T DeserializeObject<T>(string xml)
         where T : new()
    {
        if (string.IsNullOrEmpty(xml))
        {
            return new T();
        }
        try
        {
            using (var stringReader = new StringReader(xml))
            {
                var serializer = new XmlSerializer(typeof(T));
                return (T)serializer.Deserialize(stringReader);
            }
        }
        catch (Exception ex)
        {
            return new T();
        }
    }
}

Вы можете вызвать его, используя:

MyCustomObject myObject = new MyCustomObject();
string xmlString = XmlConvert.SerializeObject(myObject)
myObject = XmlConvert.DeserializeObject<MyCustomObject>(xmlString);
2

Вы можете использовать xsd.exe для создания связанных классов схемы в .Net, затем XmlSerializer для десериализации строки: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.deserialize.aspx

1

Вы можете сгенерировать класс, как описано выше, или написать их вручную:

[XmlRoot("msg")]
public class Message
{
    [XmlElement("id")]
    public string Id { get; set; }
    [XmlElement("action")]
    public string Action { get; set; }
}

Затем вы можете использовать ExtendedXmlSerializer для сериализации и десериализации.

Instalation Вы можете установить ExtendedXmlSerializer из nuget или выполнить следующую команду:

Install-Package ExtendedXmlSerializer

Сериализация:

var serializer = new ConfigurationContainer().Create();
var obj = new Message();
var xml = serializer.Serialize(obj);

Десериализация

var obj2 = serializer.Deserialize<Message>(xml);

Эта поддержка сериализатора:

  • Deserialization xml из стандартного XMLSerializer
  • Класс сериализации, структура, общий класс, примитивный тип, общий список и словарь, массив, перечисление
  • Класс сериализации с интерфейсом свойств
  • Сериализация круговой ссылки и эталонного идентификатора
  • Дезабилизация старой версии xml
  • Шифрование свойств
  • Специальный сериализатор
  • Поддержка XmlElementAttribute и XmlRootAttribute
  • POCO - все конфигурации (миграции, пользовательский сериализатор...) находятся за пределами класса

ExtendedXmlSerializer поддерживает .NET 4.5 или выше и .NET Core. Вы можете интегрировать его с WebApi и AspCore.

  • 1
    Отличный пост! Я обновил код для его модернизации в соответствии с документацией github.com/wojtpl2/ExtendedXmlSerializer
0

Упрощение ответа Дамиана,

public static T ParseXml<T>(this string value) where T : class
{
    var xmlSerializer = new XmlSerializer(typeof(T));
    using (var textReader = new StringReader(value))
    {
        return (T) xmlSerializer.Deserialize(textReader);
    }
}
0

В дополнение к другим ответам здесь вы можете естественно использовать класс XmlDocument для чтения в формате XML DOM или XmlReader, читатель с быстрой перемоткой вперед, чтобы сделать это "вручную".

0

Если у вас есть xsd сообщения xml, вы можете сгенерировать классы С# с помощью инструмента .Net xsd.exe.

Затем эти .Net-классы можно использовать для генерации xml.

-5
public string Serialize<T>(T settings)
{
    XmlSerializer serializer = new XmlSerializer(typeof(T));
    StringWriter outStream = new StringWriter();
    serializer.Serialize(outStream, settings);
    return outStream.ToString();
}
  • 4
    Это как сериализовать, а не как десериализовать.
  • 1
    Вы только что написали код здесь. Без объяснения, это бессмысленно для многих.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню