2009-03-03 17 views
129

Dato il seguente codice XML:È possibile deserializzare il codice XML nell'elenco <T>?

<?xml version="1.0"?> 
<user_list> 
    <user> 
     <id>1</id> 
     <name>Joe</name> 
    </user> 
    <user> 
     <id>2</id> 
     <name>John</name> 
    </user> 
</user_list> 

E la seguente classe:

public class User { 
    [XmlElement("id")] 
    public Int32 Id { get; set; } 

    [XmlElement("name")] 
    public String Name { get; set; } 
} 

E 'possibile utilizzare XmlSerializer deserializzare l'XML in un List<User>? In tal caso, che tipo di attributi aggiuntivi dovrò utilizzare, o quali parametri aggiuntivi devo usare per costruire l'istanza XmlSerializer?

Un array (User[]) sarebbe accettabile, se un po 'meno preferibile.

risposta

114

È possibile incapsulare lista banalmente:

using System; 
using System.Collections.Generic; 
using System.Xml.Serialization; 

[XmlRoot("user_list")] 
public class UserList 
{ 
    public UserList() {Items = new List<User>();} 
    [XmlElement("user")] 
    public List<User> Items {get;set;} 
} 
public class User 
{ 
    [XmlElement("id")] 
    public Int32 Id { get; set; } 

    [XmlElement("name")] 
    public String Name { get; set; } 
} 

static class Program 
{ 
    static void Main() 
    { 
     XmlSerializer ser= new XmlSerializer(typeof(UserList)); 
     UserList list = new UserList(); 
     list.Items.Add(new User { Id = 1, Name = "abc"}); 
     list.Items.Add(new User { Id = 2, Name = "def"}); 
     list.Items.Add(new User { Id = 3, Name = "ghi"}); 
     ser.Serialize(Console.Out, list); 
    } 
} 
+5

Bella soluzione con [XmlElement ("utente")] per evitare un ulteriore livello di elementi. Guardando questo, ho pensato per certo che avrebbe emesso un nodo o (se non avevi l'attributo XmlElement), e poi aggiungere nodi sotto quello. Ma l'ho provato e non l'ha fatto, emettendo così esattamente ciò che la domanda voleva. –

+0

E se avessi due elenchi in UserList sopra? Ho provato il tuo metodo e dice che già definisce un membro chiamato XYZ con gli stessi tipi di parametro –

+0

Non so perché questo è contrassegnato come risposta giusta. Include l'aggiunta di una classe per avvolgere l'elenco. Questo era certamente ciò che la domanda sta cercando di evitare. – DDRider62

4

Non sicuro sull'elenco <T> ma gli array sono sicuramente in grado. E un po 'di magia rende davvero facile tornare ad una lista.

public class UserHolder { 
    [XmlElement("list")] 
    public User[] Users { get; set; } 

    [XmlIgnore] 
    public List<User> UserList { get { return new List<User>(Users); } } 
} 
+1

È possibile fare a meno della classe "titolare"? –

+0

@Daniel, AFAIK, no. È necessario serializzare e deserializzare in un tipo di oggetto concreto. Non credo che la serializzazione XML supporti nativamente le classi di raccolta come inizio di una serializzazione. Non lo so al 100%. – JaredPar

+0

[XmlElement ("elenco")] deve essere [XmlArray ("elenco")]. Questo è l'unico modo in cui la deserializzazione ha funzionato per me in .NET 4.5 – eduardobr

13

Sì, serializza e deserializza un elenco <>. Assicurati di utilizzare l'attributo [XmlArray] in caso di dubbio.

[Serializable] 
public class A 
{ 
    [XmlArray] 
    public List<string> strings; 
} 

Questo funziona con Serialize() e Deserialize().

+0

Funziona per una visione simbolica? –

5

Sì, lo fa deserializzare to List <>. Non c'è bisogno di tenerlo in un array e avvolgerlo/incapsularlo in un elenco.

public class UserHolder 
{ 
    private List<User> users = null; 

    public UserHolder() 
    { 
    } 

    [XmlElement("user")] 
    public List<User> Users 
    { 
     get { return users; } 
     set { users = value; } 
    } 
} 

codice di deserializzazione,

XmlSerializer xs = new XmlSerializer(typeof(UserHolder)); 
UserHolder uh = (UserHolder)xSerializer.Deserialize(new StringReader(str)); 
15

Penso di aver trovato un modo migliore. Non devi inserire attributi nelle tue classi. Ho realizzato due metodi per la serializzazione e la deserializzazione che prendono come parametro un elenco generico.

Date un'occhiata (funziona per me):

private void SerializeParams<T>(XDocument doc, List<T> paramList) 
    { 
     System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(paramList.GetType()); 

     System.Xml.XmlWriter writer = doc.CreateWriter(); 

     serializer.Serialize(writer, paramList); 

     writer.Close();   
    } 

private List<T> DeserializeParams<T>(XDocument doc) 
    { 
     System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(List<T>)); 

     System.Xml.XmlReader reader = doc.CreateReader(); 

     List<T> result = (List<T>)serializer.Deserialize(reader); 
     reader.Close(); 

     return result; 
    } 

Così si può serializzare qualsiasi lista che si desidera! Non è necessario specificare il tipo di elenco ogni volta.

 List<AssemblyBO> list = new List<AssemblyBO>(); 
     list.Add(new AssemblyBO()); 
     list.Add(new AssemblyBO() { DisplayName = "Try", Identifier = "243242" }); 
     XDocument doc = new XDocument(); 
     SerializeParams<T>(doc, list); 
     List<AssemblyBO> newList = DeserializeParams<AssemblyBO>(doc); 
+1

Grazie per aver effettivamente risposto alla domanda. Vorrei aggiungere che per 'Lista ' l'elemento del documento dovrebbe essere chiamato 'ArrayOfMyClass'. –

2

Come su

XmlSerializer xs = new XmlSerializer(typeof(user[])); 
using (Stream ins = File.Open(@"c:\some.xml", FileMode.Open)) 
foreach (user o in (user[])xs.Deserialize(ins)) 
    userList.Add(o);  

Non particolarmente elegante, ma dovrebbe funzionare.

+2

Benvenuti in StackOverflow! È sempre meglio fornire una breve descrizione per un codice di esempio per migliorare la precisione del post :) –

26

Se si decorare la classe User con il XmlType per abbinare la capitalizzazione richiesta:

[XmlType("user")] 
public class User 
{ 
    ... 
} 

Poi il XmlRootAttribute sul XmlSerializer ctor in grado di fornire la radice desiderata e consentire la lettura diretta in List <>:

// e.g. my test to create a file 
    using (var writer = new FileStream("users.xml", FileMode.Create)) 
    { 
     XmlSerializer ser = new XmlSerializer(typeof(List<User>), 
      new XmlRootAttribute("user_list")); 
     List<User> list = new List<User>(); 
     list.Add(new User { Id = 1, Name = "Joe" }); 
     list.Add(new User { Id = 2, Name = "John" }); 
     list.Add(new User { Id = 3, Name = "June" }); 
     ser.Serialize(writer, list); 
    } 

...

// read file 
    List<User> users; 
    using (var reader = new StreamReader("users.xml")) 
    { 
     XmlSerializer deserializer = new XmlSerializer(typeof(List<User>), 
      new XmlRootAttribute("user_list")); 
     users = (List<User>)deserializer.Deserialize(reader); 
    } 

Credito: basato su answer da YK1.

+3

Dal mio punto di vista, questa è chiaramente la risposta alla domanda. La domanda riguardava la deserializzazione nell'Elenco . Tutte le altre soluzioni, tranne forse una, includono una classe di wrapping per contenere la lista, che non era certamente la domanda pubblicata, e ciò che l'autore della domanda sembra stia cercando di evitare. – DDRider62

Problemi correlati