Converti stringa XML in oggetto


179

Ricevo stringhe XML su un socket e vorrei convertirle in oggetti C #.

I messaggi sono nel formato:

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

Sono nuovo di .Net e non sono sicuro delle migliori pratiche per farlo. Ho usato JAXB per Java prima e non ero sicuro che ci fosse qualcosa di simile o se questo sarebbe stato gestito in modo diverso.


3
Hai oggetti che diventano o vuoi generare dinamicamente gli oggetti?
Stephan,


Per me questa è stata l'opzione migliore: stackoverflow.com/a/24184283/2647430
Ivan Lopez,

Risposte:


277

È necessario utilizzare lo xsd.exestrumento che viene installato con Windows SDK in una directory simile a:

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

E su computer a 64 bit:

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

E su computer Windows 10:

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

Al primo avvio, usi xsd.exee converti il ​​tuo XML di esempio in un file XSD (file di schema XML):

xsd yourfile.xml

Questo ti dà yourfile.xsd, che in un secondo passaggio, puoi convertire di nuovo usando xsd.exein una classe C #:

xsd yourfile.xsd /c

Questo dovrebbe darti un file yourfile.csche conterrà una classe C # che puoi usare per deserializzare il file XML che stai ricevendo - qualcosa del tipo:

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

Dovrebbe funzionare abbastanza bene nella maggior parte dei casi.

Aggiornamento: il serializzatore XML prenderà qualsiasi flusso come input - un file o un flusso di memoria andrà bene:

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

o usa un StringReader:

XmlSerializer serializer = new XmlSerializer(typeof(msg));
StringReader rdr = new StringReader(inputString);
msg resultingMessage = (msg)serializer.Deserialize(rdr);

Grazie per la spiegazione dettagliata. Nel mio caso, l'XML sta arrivando su un socket ed è una stringa. Come deserializzare una stringa anziché un file XML?
Steve,

5
@Steve: puoi aprire StringReader e passare il metodo Deserialize. StringReader deriva da TextReader.
Skurmedel,

Preferiresti il ​​tuo approccio a quello che Fahad ha menzionato usando Linq?
Steve,

2
@Steve: sì, deserializzare un oggetto ed essere in grado di colpire le proprietà dell'oggetto sembra molto più facile che fare un sacco di oscillazioni con elementi XML, attributi, nodi figlio ecc. Linq-to-XML è ottimo se il XML è irregolare e cambia continuamente o non è noto in anticipo.
marc_s,

7
Questo sito Web è molto più semplice dello strumento xsd IMO: xmltocsharp.azurewebsite.net
nasch,

226

Hai due possibilità.

Metodo 1. Strumento XSD


Supponi di avere il tuo file XML in questa posizione C:\path\to\xml\file.xml

  1. Apri prompt dei comandi per sviluppatori
    Puoi trovarlo in Start Menu > Programs > Microsoft Visual Studio 2012 > Visual Studio Tools O se hai Windows 8 puoi semplicemente iniziare a digitare Prompt dei comandi per sviluppatori nella schermata Start
  2. Cambiare posizione nella directory del file XML digitando cd /D "C:\path\to\xml"
  3. Crea il file XSD dal tuo file xml digitandoxsd file.xml
  4. Crea classi C # digitandoxsd /c file.xsd

E questo è tutto! Hai generato classi C # dal file xml inC:\path\to\xml\file.cs

Metodo 2: incolla speciale


Richiesto Visual Studio 2012+ con .Net Framework> = 4.5 come destinazione del progetto e componente individuale 'Windows Communication Foundation' installato

  1. Copia il contenuto del tuo file XML negli appunti
  2. Aggiungi alla tua soluzione un nuovo file di classe vuoto ( Shift+ Alt+C )
  3. Apri quel file e nel menu fai clic Edit > Paste special > Paste XML As Classes
    inserisci qui la descrizione dell'immagine

E questo è tutto!

uso


L'utilizzo è molto semplice con questa classe di supporto:

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

Tutto quello che devi fare ora è:

    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
Saluti. ri: metodo 2, devi scegliere come target .net 4.5 altrimenti l'opzione non è disponibile.
timB33

12
Il metodo 2 è ridicolmente utile! Grazie per quello Non avevo idea che esistesse.
Dominic Bindley,

1
Complimenti per il metodo 2, funziona come un fascino. Ottimo quando si tenta di analizzare semplicemente un XML a livello di codice senza dover implementare classi noiose.
Alex

1
Dovresti fare "Incolla speciale" come primo metodo, è il più semplice. Limitazione ".Net Framework> = 4.5" non è importante nel 2017.
Michael Freidgeim il

2
"Incolla XML come classi" richiede il carico di lavoro WCF per Visual Studio installato.
Lennart,

49

Prova questo metodo per convertire Xml in un oggetto. È fatto esattamente per quello che stai facendo:

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

Chiamalo usando questo codice:

YourStrongTypedEntity entity = FromXml<YourStrongTypedEntity>(YourMsgString);

6
Hai ricevuto questo errore xmlns = ''> non era previsto. "}, Hai idea?
Prashant

Il problema è che devi avere la tua classe perfettamente formata in anticipo. Forse una funzione che genera una classe quando viene dato XML? xsd.exe è hit & miss (per lo più manca per cose complesse) ...
Yumi Koizumi

1
Oh mio Dio, ho passato ore a occuparmi del serializzatore XML .nets, e questo ha funzionato subito.
christopher clark

11

Esegui semplicemente Visual Studio 2013 come amministrazione ... Copia il contenuto del tuo file Xml. Vai a Visual Studio 2013> Modifica> Incolla speciale> Incolla Xml come classi C # Creerà le tue classi c # in base al contenuto del tuo file Xml.


7

Nel caso qualcuno lo trovasse utile:

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

Puoi chiamarlo usando:

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

5

Puoi generare la classe come descritto sopra o scriverli manualmente:

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

Quindi è possibile utilizzare ExtendedXmlSerializer per serializzare e deserializzare.

Instalation È possibile installare ExtendedXmlSerializer da NuGet o eseguire il seguente comando:

Install-Package ExtendedXmlSerializer

serializzazione:

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

deserializzazione

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

Questo supporto serializzatore:

  • Deserializzazione XML da XMLSerializer standard
  • Classe di serializzazione, struct, classe generica, tipo primitivo, elenco e dizionario generici, array, enum
  • Classe di serializzazione con interfaccia di proprietà
  • Riferimento circolare di serializzazione e riferimento ID
  • Deserializzazione della vecchia versione di xml
  • Crittografia delle proprietà
  • Serializzatore personalizzato
  • Supporta XmlElementAttribute e XmlRootAttribute
  • POCO: tutte le configurazioni (migrazioni, serializzatore personalizzato ...) sono al di fuori della classe

ExtendedXmlSerializer supporta .NET 4.5 o versioni successive e .NET Core . Puoi integrarlo con WebApi e AspCore.


1
Post eccellente! Ho aggiornato il codice per modernizzarlo secondo la documentazione github.com/wojtpl2/ExtendedXmlSerializer
user1477388


2

Semplificando la grande risposta di Damian,

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

Creare un DTO come CustomObject

Utilizzare il metodo seguente per convertire la stringa XML in DTO utilizzando 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

Se hai l'xsd del messaggio xml, puoi generare classi c # usando lo strumento .Net xsd.exe.

Queste classi .Net possono quindi essere utilizzate per generare l'xml.


0

Oltre alle altre risposte qui puoi naturalmente usare la classe XmlDocument , per la lettura XML DOM-like, o XmlReader , lettore veloce solo in avanti, per farlo "a mano".


0

Un altro modo con strumenti avanzati di generazione di classi xsd to c #: xsd2code.com. Questo strumento è molto utile e potente. Ha molta più personalizzazione rispetto allo strumento xsd.exe di Visual Studio. Xsd2Code ++ può essere personalizzato per utilizzare Elenchi o Matrici e supporta schemi di grandi dimensioni con molte istruzioni di importazione.

Nota di alcune funzionalità,

  • Genera oggetti business dallo schema XSD o dal file XML al codice C # o Visual Basic flessibile.
  • Supporto da Framework 2.0 a 4.x
  • Supporta una raccolta tipizzata forte (List, ObservableCollection, MyCustomCollection).
  • Supporta proprietà automatiche.
  • Generare metodi di lettura e scrittura XML (serializzazione / deserializzazione).
  • Supporto per la creazione di database (WPF, Xamarin).
  • WCF (attributo DataMember).
  • Supporto per la codifica XML (UTF-8/32, ASCII, Unicode, personalizzato).
  • Custodia per cammello / supporto per custodia Pascal.
  • supporto di restrizione ([StringLengthAttribute = true / false], [RegularExpressionAttribute = true / false], [RangeAttribute = true / false]).
  • Supporta file XSD di grandi dimensioni e complessi.
  • Supporto di DotNet Core e standard

0

So che questa domanda è vecchia, ma mi sono imbattuto in esso e ho una risposta diversa rispetto a tutti gli altri :-)

Il solito modo (come menzionato sopra dai commentatori) è generare una classe e deserializzare il tuo XML.

Ma ( avvertimento: autopromozione spudorata qui ) Ho appena pubblicato un pacchetto di nuget, qui , con il quale non è necessario. Vai e basta:

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

Questo è letteralmente, nient'altro necessario. E, soprattutto, se il tuo xml cambia, anche il tuo oggetto cambia automaticamente.

Se preferisci scaricare la dll direttamente, la pagina github è qui .


-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
Ecco come serializzare, non come deserializzare.
alexc95,

1
Hai appena scritto il codice qui. Senza alcuna spiegazione, è insignificante per molti.
M. Haché,

Il codice non elimina i flussi
bigfoot
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.