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

179

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

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

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

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

Стив
источник
3
У вас есть объекты, которыми они становятся, или вы хотите динамически генерировать объекты?
Стефан
ищите это сообщение: http://stackoverflow.com/questions/765422/jaxb-equivalent-in-c
Aykut Çevik
Для меня это был лучший вариант: stackoverflow.com/a/24184283/2647430
Иван Лопес

Ответы:

277

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

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в класс C #:

xsd yourfile.xsd /c

Это должно дать вам файл, yourfile.csкоторый будет содержать класс C #, который вы можете использовать для десериализации получаемого вами 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);
marc_s
источник
Спасибо за подробное объяснение. В моем случае XML идет через сокет и является строкой. Как бы я десериализовал строку вместо файла XML?
Стив
5
@Steve: Вы можете открыть StringReader и передать метод Deserialize. StringReader является производным от TextReader.
Скурмедель
Вы бы предпочли свой подход тому, о котором Фахад упоминал, используя Linq?
Стив
2
@Steve: да, я бы - десериализация в объект и возможность поковыряться в свойствах объекта, кажется намного проще, чем делать много покачиваний с XML-элементами, атрибутами, дочерними узлами и т. Д. Linq-to-XML отлично подходит, если XML нерегулярен и постоянно изменяется или не известен заранее.
marc_s
7
Этот веб - сайт намного проще , чем инструмент XSD IMO: xmltocsharp.azurewebsites.net
нащий
226

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

Способ 1. XSD- инструмент


Предположим, что у вас есть файл XML в этом месте C:\path\to\xml\file.xml

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

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

Метод 2 - Специальная вставка


Требуется Visual Studio 2012+ с .Net Framework> = 4.5 в качестве цели проекта и установленным отдельным компонентом «Windows Communication Foundation».

  1. Скопируйте содержимое вашего XML-файла в буфер обмена
  2. Добавьте в свое решение новый пустой файл класса ( Shift+ Alt+ C)
  3. Откройте этот файл и в меню нажмите Edit > Paste special > Paste XML As Classes
    введите описание изображения здесь

И это все!

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


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

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, иначе опция недоступна.
timB33 12.12.13
12
Метод 2 смехотворно полезен! Спасибо за это. Я понятия не имел, что существует.
Доминик Биндли
1
Слава за метод 2, работает как шарм. Прекрасно, когда вы пытаетесь просто разобрать XML программно, без необходимости реализовывать скучные классы.
Alex
1
Вы должны сделать «Специальная вставка» в качестве первого метода - это самый простой. Ограничение ".Net Framework> = 4.5" не важно в 2017 году.
Майкл Фрейдгейм
2
«Вставить XML как классы» требует установленной рабочей нагрузки WCF для Visual Studio.
Леннарт
49

Попробуйте этот метод для преобразования 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);
RJ.
источник
6
Получил эту ошибку xmlns = ''> не ожидал. "}, Любая идея?
Prashant
Проблема в том, что вам нужно заранее сформировать свой класс. Может быть, функция, которая выводит класс при наличии XML? xsd.exe - хит и мисс (в основном не хватает сложных вещей) ...
Юми Коидзуми
1
Боже мой, я часами работал с сериализатором .nets xml, и это сработало прямо за воротами.
Христофор кларк
11

Просто запустите Visual Studio 2013 от имени администратора ... Скопируйте содержимое файла Xml. Перейдите в Visual Studio 2013> Правка> Специальная вставка> Вставить XML как классы C #. Он создаст ваши классы c # в соответствии с содержимым вашего файла XML.

user2667652
источник
7

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

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);
Razzer
источник
5

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

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

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

Установка Вы можете установить 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);

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

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

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

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

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

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);
    }
}
Сэм Джаз
источник
1

Создать DTO как CustomObject

Используйте приведенный ниже метод для преобразования XML String в DTO с использованием JAXB

private static CustomObject getCustomObject(final String ruleStr) {
    CustomObject customObject = null;
    try {
        JAXBContext jaxbContext = JAXBContext.newInstance(CustomObject.class);
        final StringReader reader = new StringReader(ruleStr);
        Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
        customObject = (CustomObject) jaxbUnmarshaller.unmarshal(reader);
    } catch (JAXBException e) {
        LOGGER.info("getCustomObject parse error: ", e);
    }
    return customObject;
}
Мохит Сингх
источник
0

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

Эти классы .Net могут быть использованы для генерации XML.

Амитабх
источник
0

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

Skurmedel
источник
0

Еще один способ с расширенными инструментами генерации классов xsd to c #: xsd2code.com. Этот инструмент очень удобный и мощный. Он имеет гораздо больше настроек, чем инструмент xsd.exe из Visual Studio. Xsd2Code ++ может быть настроен для использования списков или массивов и поддерживает большие схемы с большим количеством операторов импорта.

Обратите внимание на некоторые особенности,

  • Генерирует бизнес-объекты из схемы XSD или файла XML в гибкий код C # или Visual Basic.
  • Поддержка Framework 2.0 до 4.x
  • Поддержка строго типизированной коллекции (List, ObservableCollection, MyCustomCollection).
  • Поддержка автоматических свойств.
  • Генерация XML для чтения и записи методов (сериализация / десериализация).
  • Поддержка привязки данных (WPF, Xamarin).
  • WCF (атрибут DataMember).
  • Поддержка кодировки XML (UTF-8/32, ASCII, Unicode, Custom).
  • Чехол для верблюда / Pascal Case.
  • поддержка ограничений ([StringLengthAttribute = true / false], [RegularExpressionAttribute = true / false], [RangeAttribute = true / false]).
  • Поддержка большого и сложного файла XSD.
  • Поддержка DotNet Core и стандарта
Хаас Франк
источник
0

Я знаю, что этот вопрос старый, но я наткнулся на него, и у меня есть другой ответ, чем, ну, все остальные :-)

Обычный способ (как упоминалось выше) - создать класс и десериализовать ваш xml.

Но ( предупреждение: бесстыдная самореклама здесь ) , я только что опубликовал NuGet пакет, здесь , с которым вы не должны. Вы просто идете:

string xml = System.IO.File.ReadAllText(@"C:\test\books.xml");
var book = Dandraka.XmlUtilities.XmlSlurper.ParseText(xml);

Это буквально это, больше ничего не нужно. И, самое главное, если ваш xml изменяется, ваш объект также изменяется автоматически.

Если вы предпочитаете скачать dll напрямую, страница github находится здесь .

Джим Андракакис
источник
-7
public string Serialize<T>(T settings)
{
    XmlSerializer serializer = new XmlSerializer(typeof(T));
    StringWriter outStream = new StringWriter();
    serializer.Serialize(outStream, settings);
    return outStream.ToString();
}
Mandoleen
источник
5
Это как сериализовать, а не как десериализовать.
alexc95
1
Вы только что написали код здесь. Без объяснения причин это бессмысленно для многих.
М. Хаче
Код не выбрасывайте потоков
йети