Перетворити рядок XML в об’єкт


180

Я отримую XML-рядки через сокет і хочу перетворити їх у об'єкти C #.

Повідомлення мають форму:

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

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


3
У вас ці об'єкти стають або ви хочете динамічно генерувати об'єкти?
Стефан


Для мене це був найкращий варіант: stackoverflow.com/a/24184283/2647430
Іван Лопес

Відповіді:


277

Вам потрібно скористатися 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клас 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);

Дякую за детальне пояснення. У моєму випадку XML надходить через сокет і є рядком. Як я можу де-серіалізувати рядок замість файлу XML?
Стів

5
@Steve: Ви можете відкрити StringReader і пройти метод Deserialize. StringReader походить від TextReader.
Скурмедель

Чи віддасте перевагу своєму підходу до того, про який Фахад згадував, використовуючи Linq?
Стів

2
@Steve: так, я б - десяріалізація в об'єкт і можливість піддаватись властивостям об'єкта здається набагато простіше, ніж робити багато ворушіння з XML-елементами, атрибутами, дочірніми вузлами і т. Д. Linq-to-XML чудово, якщо XML нерегулярний і постійно змінюється, або невідомий достроково.
marc_s

7
Цей веб-сайт набагато простіше, ніж інструмент xsd IMO: xmltocsharp.azurewebsites.net
nasch

227

У вас є дві можливості.

Спосіб 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»

  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
ура. re: метод 2, вам потрібно націлити на .net 4.5, інша опція недоступна.
timB33

12
Спосіб 2 смішно корисний! Дякую за це. Я не мав ідеї, що існує.
Домінік Біндлі

1
Кудос за методом 2, працює як шарм. Чудово під час спроби просто розібрати XML програмно без необхідності впроваджувати нудні класи.
Олексій

1
Ви повинні зробити "Вставити спеціальний" як перший метод - це найпростіший. Обмеження ".Net Framework> = 4,5" не важливо в 2017 році.
Майкл Фрейджім

2
"Вставити XML як класи" вимагає завантаження WCF для Visual Studio.
Леннарт

50

Спробуйте за допомогою цього методу перетворити 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);

6
Отримав цю помилку xmlns = ''> не очікували. "}, Будь-яка ідея?
Prashant

Проблема в тому, що вам потрібно заздалегідь сформувати свій клас. Можливо, функція, яка видає клас при наданні XML? xsd.exe - хіт і міс (в основному сумую за складними речами) ...
Yumi Koizumi

1
О боже, я проводив години, торкаючись серіалізатора .nets xml, і це працювало прямо з воріт.
Крістофер Кларк

11

Просто запустіть Visual Studio 2013 в якості адміністрації ... Скопіюйте вміст файлу Xml. Перейдіть до Visual Studio 2013> Редагувати> Спеціальна вставка> Вставити Xml як C # класи. Це створить ваші класи c # відповідно до вмісту вашого файлу Xml.


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

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 - всі конфігурації (міграції, спеціальний серіалізатор ...) знаходяться поза класом

Розширена підтримкаXmlSerializer .NET 4.5 або новішої версії та .NET Core . Ви можете інтегрувати його з WebApi та AspCore.


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 в 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 , що швидко працює лише вперед, щоб зробити це "вручну".


0

Ще один спосіб із розширеними класами покоління xsd to c #: Інструменти xsd2code.com. Цей інструмент дуже зручний і потужний. Він має набагато більше налаштування, ніж інструмент xsd.exe від Visual Studio. Xsd2Code ++ можна налаштувати для використання списків або масивів і підтримує великі схеми з великою кількістю операторів імпорту.

Зверніть увагу на деякі функції,

  • Генерує бізнес-об’єкти зі схеми XSD або XML-файлу до гнучкого коду C # або Visual Basic.
  • Підтримка Framework 2.0 - 4.x
  • Підтримка сильної набраної колекції (Список, ObservableCollection, MyCustomCollection).
  • Підтримка автоматичних властивостей.
  • Створення методів читання та запису XML (серіалізація / десеріалізація).
  • Підтримка передачі даних (WPF, Xamarin).
  • WCF (атрибут DataMember).
  • Підтримка кодування XML (UTF-8/32, ASCII, Unicode, Custom).
  • Підставка для верблюда / кейс Pascal.
  • підтримка обмежень ([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();
}

5
Це як серіалізувати, а не як дезаріалізувати.
alexc95

1
Ви щойно написали код тут. Не маючи пояснень, для багатьох це безглуздо.
М. Хаше

Код не розпоряджається потоками
bigfoot
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.