2010-11-08 2 views
187

Ho una classe C# che ho ereditato. Ho "costruito" con successo l'oggetto. Ma ho bisogno di serializzare l'oggetto in XML. C'è un modo semplice per farlo?Serializzare un oggetto in XML

Sembra che la classe sia stata impostata per la serializzazione, ma non sono sicuro di come ottenere la rappresentazione XML. La mia definizione di classe si presenta così:

[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")] 
[System.SerializableAttribute()] 
[System.Diagnostics.DebuggerStepThroughAttribute()] 
[System.ComponentModel.DesignerCategoryAttribute("code")] 
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.domain.com/test")] 
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.domain.com/test", IsNullable = false)] 
public partial class MyObject 
{ 
    ... 
} 

Ecco quello che ho pensato che avrei potuto fare, ma non funziona:

MyObject o = new MyObject(); 
// Set o properties 
string xml = o.ToString(); 

Come faccio ad avere la rappresentazione XML di questo oggetto?

+0

ho sviluppato una semplice libreria di fare ottenere questo: https://github.com/aishwaryashiva/SaveXML –

+0

Vedere anche: [Serializzazione XML e deserializzazione su CodeProject] (http://www.codeproject.com/Articles/487571/XML-Serializ ation-and-Deserialization-Part) –

risposta

338

È necessario utilizzare XmlSerializer per la serializzazione XML. Di seguito è riportato uno snippet di esempio.

XmlSerializer xsSubmit = new XmlSerializer(typeof(MyObject)); 
var subReq = new MyObject(); 
var xml = ""; 

using(var sww = new StringWriter()) 
{ 
    using(XmlWriter writer = XmlWriter.Create(sww)) 
    { 
     xsSubmit.Serialize(writer, subReq); 
     xml = sww.ToString(); // Your XML 
    } 
} 
+9

Sembra funzionare perfettamente senza la riga 'XmlWriter writer = XmlWriter.Create (sww);' –

+105

'using' people use' using's! Smaltisci questi oggetti! – Liam

+8

Per avere un oggetto serializzato formattato fare: 'XmlTextWriter writer = new XmlTextWriter (sww) {Formatting = Formatting.Indented};' invece di 'XmlWriter writer = XmlWriter.Create (sww);' –

13

Per serializzare un oggetto, lo fanno:

using (StreamWriter myWriter = new StreamWriter(path, false)) 
{ 
    XmlSerializer mySerializer = new XmlSerializer(typeof(your_object_type)); 
    mySerializer.Serialize(myWriter, objectToSerialize); 
} 

Ricordiamo inoltre che per XmlSerializer per lavorare, hai bisogno di un costruttore senza parametri.

+1

Questo mi stava facendo impazzire. Non riuscivo a capire perché era sempre vuoto. Poi ho capito che non avevo un costruttore senza parametri dopo aver letto la tua risposta. Grazie. – Andy

6

È un po 'più complicato che chiamare il metodo ToString della classe, ma non molto.

Ecco una semplice funzione drop-in che è possibile utilizzare per serializzare qualsiasi tipo di oggetto. Restituisce una stringa contenente i contenuti XML serializzati:

public string SerializeObject(object obj) 
{ 
    System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument(); 
    System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(obj.GetType()); 
    using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) { 
     serializer.Serialize(ms, obj); 
     ms.Position = 0; 
     xmlDoc.Load(ms); 
     return xmlDoc.InnerXml; 
    } 
} 
27

È possibile utilizzare la funzione come di seguito per ottenere l'XML serializzato da qualsiasi oggetto.

public static bool Serialize<T>(T value, ref string serializeXml) 
{ 
    if (value == null) 
    { 
     return false; 
    } 
    try 
    { 
     XmlSerializer xmlserializer = new XmlSerializer(typeof(T)); 
     StringWriter stringWriter = new StringWriter(); 
     XmlWriter writer = XmlWriter.Create(stringWriter); 

     xmlserializer.Serialize(writer, value); 

     serializeXml = stringWriter.ToString(); 

     writer.Close(); 
     return true; 
    } 
    catch (Exception ex) 
    { 
     return false; 
    } 
} 

È possibile chiamare questo dal client.

28

La seguente funzione può essere copiata su qualsiasi oggetto per aggiungere una funzione di salvataggio XML utilizzando lo spazio dei nomi System.Xml.

/// <summary> 
/// Saves to an xml file 
/// </summary> 
/// <param name="FileName">File path of the new xml file</param> 
public void Save(string FileName) 
{ 
    using (var writer = new System.IO.StreamWriter(FileName)) 
    { 
     var serializer = new XmlSerializer(this.GetType()); 
     serializer.Serialize(writer, this); 
     writer.Flush(); 
    } 
} 

per creare l'oggetto dal file salvato, aggiungere la seguente funzione e sostituire [ObjectType] con il tipo di oggetto da creare.

/// <summary> 
/// Load an object from an xml file 
/// </summary> 
/// <param name="FileName">Xml file name</param> 
/// <returns>The object created from the xml file</returns> 
public static [ObjectType] Load(string FileName) 
{ 
    using (var stream = System.IO.File.OpenRead(FileName)) 
    { 
     var serializer = new XmlSerializer(typeof([ObjectType])); 
     return serializer.Deserialize(stream) as [ObjectType]; 
    } 
} 
+0

'writer.Flush()' è ridondante in un blocco 'using' - il metodo' Dispose() 'di' writer' lo svuoterà per te. – bavaza

+1

La mia esperienza ha rilevato che non è vero. Con dati più grandi, l'istruzione using disporrà lo stream prima che il buffer venga cancellato. Il 100% consiglia esplicitamente di chiamare flush. –

+1

writer.Flush() NON è ridondante, DEVE essere lì. Senza Flush, può succedere che una parte di dati sia ancora nel buffer StreamWriter e il file venga eliminato e alcuni dati manchino. – qub1n

79

Ho modificato il mio per restituire una stringa piuttosto che utilizzare una variabile di riferimento come di seguito.

public static string Serialize<T>(this T value) 
{ 
    if (value == null) 
    { 
     return string.Empty; 
    } 
    try 
    { 
     var xmlserializer = new XmlSerializer(typeof(T)); 
     var stringWriter = new StringWriter(); 
     using (var writer = XmlWriter.Create(stringWriter)) 
     { 
      xmlserializer.Serialize(writer, value); 
      return stringWriter.ToString(); 
     } 
    } 
    catch (Exception ex) 
    { 
     throw new Exception("An error occurred", ex); 
    } 
} 

Il suo utilizzo sarebbe stato così: class

var xmlString = obj.Serialize(); 
+7

soluzione molto bella, mi piace il modo in cui hai implementato questo come metodo di estensione – Spyros

+34

Una cosa che suggerirei qui: rimuovere il blocco try ... catch. Non ti dà alcun vantaggio e semplicemente offusca l'errore che viene lanciato. – jammycakes

+1

Non è necessario utilizzare anche lo stringwriter? ad esempio: using (var stringWriter = new StringWriter()) –

23

Estensione:

using System.IO; 
using System.Xml; 
using System.Xml.Serialization; 

namespace MyProj.Extensions 
{ 
    public static class XmlExtension 
    { 
     public static string Serialize<T>(this T value) 
     { 
      if (value == null) return string.Empty; 

      var xmlSerializer = new XmlSerializer(typeof(T)); 

      using (var stringWriter = new StringWriter()) 
      { 
       using (var xmlWriter = XmlWriter.Create(stringWriter,new XmlWriterSettings{Indent = true})) 
       { 
        xmlSerializer.Serialize(xmlWriter, value); 
        return stringWriter.ToString(); 
       }  
      } 
     } 
    } 
} 

Usage:

Foo foo = new Foo{MyProperty="I have been serialized"}; 

string xml = foo.Serialize(); 

Proprio riferimento allo spazio dei nomi trattenere il metodo di estensione nel file che ti piacerebbe t o utilizzarlo e funzionerà (nel mio esempio sarebbe: using MyProj.Extensions;)

Si noti che se si desidera rendere il metodo di estensione specifico solo per una particolare classe (ad esempio, Foo), è possibile sostituire il Argomento T nel metodo di estensione, ad es.

public static string Serialize(this Foo value){...}

+0

Ho provato questo codice, poiché sembra essere il più pulito, ma nell'ultima riga non offre il metodo "Serialize()". Cosa mi manca? – ditto1977

+0

@ user312305 Le mie più sincere scuse, ho pubblicato la versione sbagliata. Si prega di vedere la mia risposta modificata, senza bisogno di ereditarietà, si applica solo a tutti gli oggetti! –

+0

Molto carino, amico mio! Ora uso solo 'XmlExtension.Serialize (foo);' e tutto va bene! Grazie molto. – ditto1977

1

Oppure è possibile aggiungere questo metodo per l'oggetto:

public void Save(string filename) 
    { 
     var ser = new XmlSerializer(this.GetType()); 
     using (var stream = new FileStream(filename, FileMode.Create)) 
      ser.Serialize(stream, this); 
    } 
12

inizierò con la risposta copia di Ben Gripka:

public void Save(string FileName) 
{ 
    using (var writer = new System.IO.StreamWriter(FileName)) 
    { 
     var serializer = new XmlSerializer(this.GetType()); 
     serializer.Serialize(writer, this); 
     writer.Flush(); 
    } 
} 

Ho usato questo codice precedente. Ma la realtà ha dimostrato che questa soluzione è un po 'problematica. Di solito la maggior parte dei programmatori serializza semplicemente le impostazioni di salvataggio e deserializzazione sul carico. Questo è uno scenario ottimistico. Una volta che la serializzazione ha avuto esito negativo, a causa di qualche motivo, il file è parzialmente scritto, il file XML non è completo e non è valido. Di conseguenza, la deserializzazione dell'XML non funziona e l'applicazione potrebbe bloccarsi all'avvio. Se il file non è enorme, suggerisco di serializzare prima l'oggetto su MemoryStream quindi scrivere lo stream sul file. Questo caso è particolarmente importante se c'è qualche complicata serializzazione personalizzata. Non puoi mai testare tutti i casi.

public void Save(string fileName) 
{ 
    //first serialize the object to memory stream, 
    //in case of exception, the original file is not corrupted 
    using (MemoryStream ms = new MemoryStream()) 
    { 
     var writer = new System.IO.StreamWriter(ms);  
     var serializer = new XmlSerializer(this.GetType()); 
     serializer.Serialize(writer, this); 
     writer.Flush(); 

     //if the serialization succeed, rewrite the file. 
     File.WriteAllBytes(fileName, ms.ToArray()); 
    } 
} 

La deserializzazione nello scenario del mondo reale dovrebbe contare con il file di serializzazione corrotto, accade qualche volta. La funzione di carico fornita da Ben Gripka va bene.

public static [ObjectType] Load(string fileName) 
{ 
    using (var stream = System.IO.File.OpenRead(fileName)) 
    { 
     var serializer = new XmlSerializer(typeof([ObjectType])); 
     return serializer.Deserialize(stream) as [ObjectType];   
    }  
} 

E potrebbe essere avvolto da qualche scenario di recupero. È adatto per file di impostazioni o altri file che possono essere eliminati in caso di problemi.

public static [ObjectType] LoadWithRecovery(string fileName) 
{ 
    try 
    { 
     return Load(fileName); 
    } 
    catch(Excetion) 
    { 
     File.Delete(fileName); //delete corrupted settings file 
     return GetFactorySettings(); 
    } 
} 
2
string FilePath = ConfigurationReader.FileLocation; //Getting path value from web.config    
    XmlSerializer serializer = new XmlSerializer(typeof(Devices)); //typeof(object) 
      MemoryStream memStream = new MemoryStream(); 
      serializer.Serialize(memStream, lstDevices);//lstdevices : I take result as a list. 
      FileStream file = new FileStream(folderName + "\\Data.xml", FileMode.Create, FileAccess.ReadWrite); //foldername:Specify the path to store the xml file 
      memStream.WriteTo(file); 
      file.Close(); 

È possibile creare e memorizzare il risultato come file XML nella posizione desiderata.

1

il mio codice di lavoro. Restituisce utf8 xml abilita lo spazio dei nomi vuoto.

// override StringWriter 
public class Utf8StringWriter : StringWriter 
{ 
    public override Encoding Encoding => Encoding.UTF8; 
} 

private string GenerateXmlResponse(Object obj) 
{  
    Type t = obj.GetType(); 

    var xml = ""; 

    using (StringWriter sww = new Utf8StringWriter()) 
    { 
     using (XmlWriter writer = XmlWriter.Create(sww)) 
     { 
      var ns = new XmlSerializerNamespaces(); 
      // add empty namespace 
      ns.Add("", ""); 
      XmlSerializer xsSubmit = new XmlSerializer(t); 
      xsSubmit.Serialize(writer, obj, ns); 
      xml = sww.ToString(); // Your XML 
     } 
    } 
    return xml; 
} 

esempio restituisce risposta Yandex api pagamento Aviso url:

<?xml version="1.0" encoding="utf-8"?><paymentAvisoResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" performedDatetime="2017-09-01T16:22:08.9747654+07:00" code="0" shopId="54321" invoiceId="12345" orderSumAmount="10643" /> 
0

Ecco un codice di base che aiuterà la serializzazione degli oggetti C# in XML:

using System; 

public class clsPerson 
{ 
    public string FirstName; 
    public string MI; 
    public string LastName; 
} 

class class1 
{ 
    static void Main(string[] args) 
    { 
     clsPerson p=new clsPerson(); 
     p.FirstName = "Jeff"; 
     p.MI = "A"; 
     p.LastName = "Price"; 
     System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(p.GetType()); 
     x.Serialize(Console.Out, p); 
     Console.WriteLine(); 
     Console.ReadLine(); 
    } 
}