Konwertuj ciąg XML na obiekt

179

Otrzymuję ciągi XML przez gniazdo i chciałbym przekonwertować je na obiekty C #.

Wiadomości mają postać:

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

Jestem nowy w .Net i nie jestem pewien najlepszych praktyk w tym zakresie. Wcześniej korzystałem z JAXB dla Javy i nie byłem pewien, czy istnieje coś podobnego, czy też byłoby inaczej.

Steve
źródło
3
Czy masz obiekty, które się stają, czy chcesz dynamicznie generować obiekty?
Stephan
Dla mnie była to najlepsza opcja: stackoverflow.com/a/24184283/2647430
Ivan Lopez

Odpowiedzi:

277

Musisz użyć xsd.exenarzędzia instalowanego wraz z zestawem Windows SDK w katalogu podobnym do:

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

I na komputerach 64-bitowych:

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

A na komputerach z systemem Windows 10:

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

Przy pierwszym uruchomieniu używasz xsd.exei konwertujesz przykładowy plik XML na plik XSD (plik schematu XML):

xsd yourfile.xml

To daje ci yourfile.xsd, co w drugim kroku, możesz ponownie przekonwertować za xsd.exepomocą klasy C #:

xsd yourfile.xsd /c

To powinno dać ci plik, yourfile.csktóry będzie zawierał klasę C #, której możesz użyć do deserializacji otrzymanego pliku XML - coś takiego:

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

Powinien działać całkiem dobrze w większości przypadków.

Aktualizacja: serializator XML pobierze dowolny strumień jako dane wejściowe - strumień pliku lub pamięci będzie w porządku:

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

lub użyj StringReader:

XmlSerializer serializer = new XmlSerializer(typeof(msg));
StringReader rdr = new StringReader(inputString);
msg resultingMessage = (msg)serializer.Deserialize(rdr);
marc_s
źródło
Dziękuję za szczegółowe wyjaśnienie. W moim przypadku XML nadchodzi przez gniazdo i jest ciągiem. Jak usunąć serializację ciągu zamiast pliku XML?
Steve,
5
@ Steve: Możesz otworzyć StringReader i przekazać metodę Deserialize. StringReader pochodzi z TextReader.
Skurmedel
Czy wolałbyś swoje podejście do tego, o którym Fahad wspomniał przy użyciu Linq?
Steve,
2
@Steve: tak, zrobiłbym - deserializacja w obiekt i umiejętność szturchania właściwości obiektu wydaje się o wiele łatwiejsza niż robienie wielu ruchów z elementami XML, atrybutami, węzłami potomnymi itp. Linq-to-XML jest świetny, jeśli XML jest nieregularny i zmienia się cały czas lub nie jest znany z góry.
marc_s
7
Ta strona jest znacznie łatwiejsza niż narzędzie xsd IMO: xmltocsharp.azurewebsites.net
nasch
226

Masz dwie możliwości.

Metoda 1. Narzędzie XSD


Załóżmy, że masz plik XML w tej lokalizacji C:\path\to\xml\file.xml

  1. Otwórz wiersz polecenia programisty
    Możesz go znaleźć w Start Menu > Programs > Microsoft Visual Studio 2012 > Visual Studio Tools Lub jeśli masz system Windows 8, możesz po prostu zacząć pisać wiersz polecenia programisty na ekranie Start
  2. Zmień lokalizację na katalog plików XML, wpisując cd /D "C:\path\to\xml"
  3. Utwórz plik XSD z pliku xml, wpisującxsd file.xml
  4. Utwórz klasy C # , wpisującxsd /c file.xsd

I to wszystko! Wygenerowałeś klasy C # z pliku xml wC:\path\to\xml\file.cs

Metoda 2 - Wklej specjalnie


Wymagany program Visual Studio 2012+ z .Net Framework> = 4.5 jako celem projektu i zainstalowanym indywidualnym komponentem „Windows Communication Foundation”

  1. Skopiuj zawartość pliku XML do schowka
  2. Dodaj do swojego rozwiązania nowy, pusty plik klasy ( Shift+ Alt+ C)
  3. Otwórz ten plik i kliknij menu Edit > Paste special > Paste XML As Classes
    wprowadź opis zdjęcia tutaj

I to wszystko!

Stosowanie


Użycie tej klasy pomocniczej jest bardzo proste:

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

Wszystko, co musisz teraz zrobić, to:

    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>();
Damian Drygiel
źródło
7
Twoje zdrowie. Odp: metoda 2, musisz kierować na .net 4.5, w przeciwnym razie opcja nie będzie dostępna.
timB33
12
Metoda 2 jest absurdalnie przydatna! Dziękuję za to. Nie miałem pojęcia, że ​​istnieje.
Dominic Bindley,
1
Kudos dla metody 2 działa jak urok. Świetne, gdy próbujesz po prostu parsować programowo XML bez konieczności implementowania nudnych klas.
Alex
1
Powinieneś zrobić „Wklej specjalnie” jako pierwszą metodę - jest najprostsza. Ograniczenie „.Net Framework> = 4.5” nie jest ważne w 2017 roku.
Michael Freidgeim
2
„Wklej XML jako klasy” wymaga zainstalowanego obciążenia WCF dla Visual Studio.
Lennart,
49

Wypróbuj tę metodę, aby przekonwertować Xml na obiekt. Jest przeznaczony do tego, co robisz:

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

Zadzwoń, używając tego kodu:

YourStrongTypedEntity entity = FromXml<YourStrongTypedEntity>(YourMsgString);
RJ.
źródło
6
Wystąpił ten błąd xmlns = ''> nie oczekiwano. "}, Jakiś pomysł?
Prashant,
Problem polega na tym, że musisz mieć odpowiednio uformowaną klasę z góry. Może funkcja, która generuje klasę, gdy otrzyma XML? xsd.exe jest hit & miss (przeważnie brak w przypadku skomplikowanych rzeczy) ...
Yumi Koizumi
1
O mój boże spędziłem godziny na rozwiązywaniu problemów z serializatorem .nets xml i to zadziałało od razu.
Christopher Clark
11

Po prostu uruchom Visual Studio 2013 jako Administracja ... Skopiuj zawartość pliku Xml .. Przejdź do Visual Studio 2013> Edytuj> Wklej specjalnie> Wklej Xml jako klasy C # Stworzy on twoje klasy c # zgodnie z zawartością pliku Xml.

użytkownik2667652
źródło
7

Na wypadek, gdyby ktoś uznał to za przydatne:

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

Możesz to nazwać za pomocą:

MyCustomObject myObject = new MyCustomObject();
string xmlString = XmlConvert.SerializeObject(myObject)
myObject = XmlConvert.DeserializeObject<MyCustomObject>(xmlString);
Razzer
źródło
5

Możesz wygenerować klasę zgodnie z powyższym opisem lub napisać ją ręcznie:

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

Następnie możesz użyć ExtendedXmlSerializer do serializacji i deserializacji.

Instalacja Możesz zainstalować ExtendedXmlSerializer z nuget lub uruchomić następującą komendę:

Install-Package ExtendedXmlSerializer

Serializacja:

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

Deserializacja

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

Obsługa serializatora:

  • Deserializacja xml ze standardowego XMLSerializer
  • Klasa szeregowania, struct, klasa ogólna, typ pierwotny, lista ogólna i słownik, tablica, wyliczanie
  • Klasa serializacji z interfejsem właściwości
  • Numer referencyjny okólnika serializacji i identyfikator referencyjny
  • Deserializacja starej wersji xml
  • Szyfrowanie własności
  • Niestandardowy serializator
  • Obsługa XmlElementAttribute i XmlRootAttribute
  • POCO - wszystkie konfiguracje (migracje, niestandardowy serializator ...) są poza klasą

Obsługa ExtendedXmlSerializer .NET 4.5 lub nowszy i .NET Core . Możesz zintegrować go z WebApi i AspCore.

Wojtpl2
źródło
1
Doskonały post! Zaktualizowałem kod, aby go zmodernizować zgodnie z dokumentacją github.com/wojtpl2/ExtendedXmlSerializer
użytkownik1477388
2

Upraszczając świetną odpowiedź Damiana,

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);
    }
}
Sam Jazz
źródło
1

Utwórz DTO jako CustomObject

Użyj poniższej metody, aby przekonwertować ciąg XML na DTO przy użyciu 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;
}
Mohit Singh
źródło
0

Jeśli masz xsd wiadomości xml, możesz wygenerować klasy c # za pomocą narzędzia .Net xsd.exe.

Tych klas .Net można następnie użyć do wygenerowania pliku XML.

Amitabh
źródło
0

Oprócz innych odpowiedzi tutaj możesz oczywiście użyć klasy XmlDocument do odczytu podobnego do DOM XML lub XmlReader , szybkiego czytnika tylko do przodu, aby zrobić to „ręcznie”.

Skurmedel
źródło
0

Innym sposobem jest Zaawansowane generowanie klas xsd do c # Narzędzia: xsd2code.com. To narzędzie jest bardzo przydatne i wydajne. Ma o wiele więcej dostosowań niż narzędzie xsd.exe z Visual Studio. Xsd2Code ++ można dostosować do korzystania z list lub tablic i obsługuje duże schematy z dużą ilością instrukcji importu.

Uwaga niektórych funkcji,

  • Generuje obiekty biznesowe ze schematu XSD lub pliku XML do elastycznego kodu C # lub Visual Basic.
  • Support Framework 2.0 do 4.x
  • Obsługuje silną kolekcję typów (List, ObservableCollection, MyCustomCollection).
  • Obsługuje właściwości automatyczne.
  • Generuj metody odczytu i zapisu XML (serializacja / deserializacja).
  • Obsługa wiązania danych (WPF, Xamarin).
  • WCF (atrybut DataMember).
  • Obsługa kodowania XML (UTF-8/32, ASCII, Unicode, Custom).
  • Obsługa futerału na wielbłądy / Pascala.
  • obsługa ograniczeń ([StringLengthAttribute = true / false], [RegularExpressionAttribute = true / false], [RangeAttribute = true / false]).
  • Obsługuje duży i złożony plik XSD.
  • Obsługa DotNet Core i standardu
Haas Franck
źródło
0

Wiem, że to pytanie jest stare, ale natknąłem się na nie i mam inną odpowiedź niż cóż, wszyscy inni :-)

Zwykłym sposobem (jak wspomniano powyżej komentatorzy) jest wygenerowanie klasy i usunięcie serializacji pliku xml.

Ale ( uwaga: bezwstydny autopromocji tutaj ) właśnie opublikowała pakiet Nuget, tutaj , z którą nie trzeba. Po prostu idź:

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

To dosłownie tyle, nic więcej nie jest potrzebne. A co najważniejsze, jeśli twój xml się zmieni, twój obiekt również zmieni się automatycznie.

Jeśli wolisz pobrać dll bezpośrednio, strona github jest tutaj .

Jim Andrakakis
źródło
-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
źródło
5
To jak serializować, a nie jak deserializować.
alexc95
1
Właśnie napisałeś tutaj kod. Bez wyjaśnienia dla wielu nie ma to znaczenia.
M. Haché,
Kod nie usuwa strumieni
bigfoot